I'm trying to set up some automatic unit testing for a project. I have some functions which, as a side effect occasionally call another function. I want to write a unit test which tests that the second function gets called but I'm stumped. Below is pseudocode example:
def a(self):
data = self.get()
if len(data) > 3500:
self.b()
# Bunch of other magic, which is easy to test.
def b(self):
serial.write("\x00\x01\x02")
How do I test that b()
-gets called?
You can mock the function b
using mock module and check if it was called. Here's an example:
import unittest
from mock import patch
def a(n):
if n > 10:
b()
def b():
print "test"
class MyTestCase(unittest.TestCase):
@patch('__main__.b')
def test_b_called(self, mock):
a(11)
self.assertTrue(mock.called)
@patch('__main__.b')
def test_b_not_called(self, mock):
a(10)
self.assertFalse(mock.called)
if __name__ == "__main__":
unittest.main()
Also see:
- Assert that a method was called in a Python unit test
- Mocking a class: Mock() or patch()?
Hope that helps.
Various solutions are possible for this thing. But first, I have to point out that unit testing is meant for testing units; what a unit is can be a matter of viewing things. In your case I'd say a unit is the function a()
because you would like to test that your unit behaves correctly, meaning it calls function b()
at the right spot. A different view would be to say that functions a()
and b()
are a unit. Then you do not like to check whether function b()
gets called, you just want to test the result of the call of function a()
. So make up your mind which suits your case best.
In case you really want to test function a()
as a unit, you should prepare your unit to being tested. In your case that could be done by adding to it an additional argument (which defaults to function b
) and which will be used instead of the hard-coded function b()
call in a()
:
def a(self, subfunction=None):
is subfunction is None: # for testing
subfunction = self.b
data = self.get()
if len(data) > 3500:
subfunction()
Now you can inject (during testing) a helper function which just informs the test that it got called:
store = None
def injected(*args, **kwargs):
global store
store = args, kwargs
obj.a(subfunction=injected)
# now check if global store is set properly