Sometimes a unit test needs to do more than validate the good or correct path, what about failure scenarios? Let’s consider a search function, it returns an object when it finds what’s being requested but throws an exception when it can’t, any calling method would need to handle that exception and then behave accordingly. Here’s an example implementation;
|if username == "user1":|
|return dict(name="user1", id_no="12345")|
If the user exists, in this case if the calling function asked for user1, find_user gives back a dict and does_user_exist would return true.
If the user does not exist, i.e. the calling function passed in anything else, find_user throws an exception which does_user_exist handles, it then returns false.
Now to the point of this post, we want to test does_user_exist but we want to cover the both of the scenarios above. How do we have our unit test force an exception to be thrown? Easy! We just give our mock a “side_effect”, here’s the relevant information from the docs.
>>> mock = Mock(side_effect=KeyError('foo')) >>> mock() Traceback (most recent call last): ... KeyError: 'foo'
Here’s what it looks like in a test;
|with mock.patch("exception_example.find_user", autospec=True, side_effect=Exception):|
|if __name__ == '__main__':|
Here’s the result of me running this test;
Nice and simple! “side_effect”, is very helpful as it can also be used for when you want to return different values per call.
>>> mock.side_effect = [5, 4, 3, 2, 1] >>> mock(), mock(), mock() (5, 4, 3)
Take a look here, for more information.
Thank you again for reading, in the next (and final) post of this series, we will be taking a look at the implications of writing good unit tests.