In answer to Is testable code better code? I showed how time-dependent code could be testable by using mocks rather than modifying the implementation:
def time_of_day():
return datetime.datetime.utcnow().strftime('%H:%M:%S')
Test code:
@unittest.patch('datetime.datetime.utcnow')
def test_handle_leap_second(self, utcnow_mock):
utcnow_mock.return_value = datetime.datetime(
year=2015, month=6, day=30, hour=23, minute=59, second=60)
actual = time_of_day()
expected = '23:59:60'
self.assertEquals(actual, expected)
The problem here (apart from Python not handling leap seconds) is that the test code assumes that utcnow
will return a datetime.datetime
object in absolutely all situations. That may be true right now for this specific function with the current interpreter etc., but if the return type changes for whatever reason the test will be passing when it probably should be failing. So for a robust test suite it would be better to guarantee that the mock return value has the same class as the original function return value. This is obviously only possible in languages where the return type is enforced by the compiler or interpreter. You could work around this by modifying a return value of the original function rather than creating your own:
utcnow_mock.return_value = datetime.datetime.utcnow().replace(
year=2015, month=6, day=30, hour=23, minute=59, second=60)
Now we're operating with a different set of assumptions:
replace
modifies the object returned byutcnow
rather than returning some different object. This will not be an issue if the relevant object properties are writable.utcnow
always returns objects with the same class.
Which method is more likely to produce a robust test suite? Please consider that unlike this example creating and then modifying an object may be simpler than creating it with the correct properties from scratch.