Reputation: 6087
I have a method which looks like this:
def foo(self):
if not self.started:
self.start()
return None
# do some other stuff...
self.bar()
return self.baz()
I am writing a test called test_foo_calls_start_if_not_already_started_and_then_returns_immediately
.
Testing if we called start
is easy:
with mock.patch.object(Thing, 'start') as mock_start:
thing = Thing()
thing.foo()
self.assertTrue(mock_start.called)
But how would I test that the function then returns straight after? I guess I could mock bar and baz and check that they aren't called, but that would be a pain to maintain.
Upvotes: 0
Views: 864
Reputation: 15153
It is hard to know without seeing more code, but I would say that a technique is to use the very next function call on self
and assert that was not called. And also if None is only returned if not started, you have strong point there.
Assuming self.bar()
is the immediate call, patch bar
and then just check that it was not called, as easy as...
assert not mock_start.calls
I however prefer to have very short unittests, and monkey-patch the methods (if not using some kind of dependency injection), instead of using the context manager. The partially mocked object is anyway discarded right away, so it is safe to do so. Something like this:
def test1(self):
thing = Thing()
thing.started = False # Maybe it would make sense to include this
thing.start = Mock()
thing.bar = Mock()
res = thing.foo()
assert res is None
assert thing.start.called
assert not thing.bar.called
The mocking frameworks can ease a lot the testing activities, but at the end the testability boils down to your code and its quality. General hints are: return meaningful values, re-factor your code into smaller methods that allow checking calls more precisely, either mutate state or return a value, but not both, etc.
Upvotes: 1