I'm having issue with arranging code to make it easily testable. I have 2 major modules in my code: cache generator and modifier builder, both have approximately the same level of complexity. Modifier builder is used in one of the methods of child objects of cache generator.
I already have full test suite which covers functionality of modifier builder. I want to add tests which cover all functionality of cache generator, but in order to significantly reduce complexity of these tests, i need to replace modifier builder with some stub, which returns predefined 'canned data' based on the arguments i passed to it.
My actual problem lies within the choosing the way of replacing real modifier builder with stub, which looks good code-wise and which is still convenient for testing. Take a look at following code:
Code from GitHub:
cacheGenerator / generator.py:
class CacheGenerator:
def __init__(self, logger):
...
self._converter = Converter(logger)
def run(self, dataHandler):
...
data = self._converter.convert(data)
cacheGenerator / converter.py:
class Converter:
...
def convert(self, data):
...
self._buildModifiers(data)
def _buildModifiers(self, data):
...
builder = ModifierBuilder(data['expressions'], self._logger)
...
modifiers, buildStatus = builder.buildEffect(...)
What are the ways of replacing modifier builder with stub? I suppose at least next few variants exist:
- Changes to code: Instantiate modifier builder in converter's init() and assign its instance as object attribute. For testing - make subclass of real converter, overriding init(), where we substitute real modifier builder with stub, then subclassing cache generator, replacing real converter with subclassed one in similar way. However, such approach will require modification of modifier builder: i will need to split data loading from init() method, which is undesirable
- Like 1), but move parts of Converter()._buildModifiers() method, which work with modifier builder, to separate methods to make them easily overriddable
- Like 1), but specify just modifier builder class (not instance) in cleaner's init(). This allows us to keep modifier builder as-is.
- Passing modifier builder class from the very top of cache generator (so that class we need to replace for testing is controllable by cache generator instantiation)
- Any other variants exist? Like some import magic?
Some of variants among 1-4 look acceptable, but ideally I'd like to keep code as close as possible (to original), so I'm investigating alternative ways of stub'bing child objects.