Is there any equivalent of strict mocks in python? Some mechanism to report unintended call of mocked methods (action.step2() in this example), just like this in GoogleMock framework.
class Action:
def step1(self, arg):
return False
def step2(self, arg):
return False
def algorithm(action):
action.step1('111')
action.step2('222')
return True
class TestAlgorithm(unittest.TestCase):
def test_algorithm(self):
actionMock = mock.create_autospec(Action)
self.assertTrue(algorithm(actionMock))
actionMock.step1.assert_called_once_with('111')
Looks like it's not supported out of the box. However there are at least two approaches on how to achieve the same result.
According to mock documentation
spec: This can be either a list of strings or an existing object (a class or instance) that acts as the specification for the mock object. If you pass in an object then a list of strings is formed by calling dir on the object (excluding unsupported magic attributes and methods). Accessing any attribute not in this list will raise an AttributeError.
So, in order to fail your test example just replace
actionMock = mock.create_autospec(Action)
to
actionMock = mock.Mock(spec=['step1'])
Such an approach have certain drawbacks compared to passing class or instance as spec
argument, as you have to pass all the allowed methods and than set up expectations on them, effectively registering them twice. Also, if you need to restrict a subset of methods you have to pass list of all methods execept those. This can be achieved as follows:
all_members = dir(Action) # according to docs this is what's happening behind the scenes
all_members.remove('step2') # remove all unwanted methods
actionMock = mock.Mock(spec=all_members)
Alternative approach would be to excplicitly set failures on methods you don't want to be called:
def test_algorithm(self):
actionMock = mock.create_autospec(Action)
actionMock.step2.side_effect = AttributeError("Called step2") # <<< like this
self.assertTrue(algorithm(actionMock))
actionMock.step1.assert_called_once_with('111')
This have some limitations as well: you've got to set errors as well as expectations.
As a final note, one radical solution to the problem would be to patch mock
to add strict
parameter to Mock
constructor and send a pull request. Than either it would be accepted or mock
maintainers will point out on how to achieve that. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With