开发者

Testing call order across mock objects with Mox and Python

I'm testing a function that obtains a skeleton object from one helper object, modifies it using a second helper, and passes the modified object back to the first helper. Something along the lines of:

class ReadModifyUpdate(object):
    def __init__(self, store, modifier):
        self._store = store
        self._modifier = modifier

    def modify(key):
        record = self._store.read(key)
        self._modifier.modify(record)
        self._store.update(开发者_运维问答key, record)

Using Python and Mox, we can test this with:

class ReadModifyUpdateTest(mox.MoxTestBase):
    def test_modify(self):
        mock_record = self.mox.CreateMockAnthing()
        mock_store = self.mox.CreateMockAnything()
        mock_modifier = self.mox.CreateMockAnything()

        mock_store.read("test_key").AndReturn(mock_record)
        mock_modifier.modify(mock_record)
        mock_store.update("test_key", mock_record)
        self.mox.ReplayAll()

        updater = ReadModifyUpdate(mock_store, mock_modifier)
        updater.modify("test_key")

...but this doesn't catch the bug in which store.update() is inadvertently called before modifier.modify(). Is there a good way, in Mox, to check the order of methods called on multiple mocks? Something like EasyMock's MocksControl object?


Maybe not the best solution but you could try to use one mock that you give twice to your object under test. You then have control over the call order.

class ReadModifyUpdateTest(mox.MoxTestBase):
    def test_modify(self):
        mock_record = self.mox.CreateMockAnthing()
        mock_storeModifier = self.mox.CreateMockAnything()

        mock_storeModifier.read("test_key").AndReturn(mock_record)
        mock_storeModifier.modify(mock_record)
        mock_storeModifier.update("test_key", mock_record)
        self.mox.ReplayAll()

        updater = ReadModifyUpdate(mock_storeModifier, mock_storeModifier)
        updater.modify("test_key")


To provide an answer to my own question - I've currently got this working using a side effect which checks the call order.

Defining a helper class:

class OrderedCallSequence(object):
    def __init__(self, test_case):
        self._expectation_count = 0
        self._evaluated = 0
        self._test_case = test_case

    def assertOrder(self):
        self._expectation_count += 1
        expected_position = self._expectation_count

        def side_effect(*args, **kwargs):
            self._evaluated += 1
            self._test_case.assertEquals(self._evaluated, expected_position,
                                         msg="Invoked in incorrect sequence")
        return side_effect

...the test case becomes:

class ReadModifyUpdateTest(mox.MoxTestBase):
    def test_modify(self):
        mock_record = self.mox.CreateMockAnthing()
        mock_store = self.mox.CreateMockAnything()
        mock_modifier = self.mox.CreateMockAnything()

        sequence = OrderedCallSequence(self)
        mock_store.read("test_key").WithSideEffects(sequence.assertOrder()).AndReturn(mock_record)
        mock_modifier.modify(mock_record).WithSideEffects(sequence.assertOrder())
        mock_store.update("test_key", mock_record).WithSideEffects(sequence.assertOrder())
        self.mox.ReplayAll()

        updater = ReadModifyUpdate(mock_store, mock_modifier)
        updater.modify("test_key")
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜