【问题标题】:How to verify a .__getitem__() call in a Mock mock_calls list during unit testing如何在单元测试期间验证 Mock mock_calls 列表中的 .__getitem__() 调用
【发布时间】:2013-09-19 21:14:52
【问题描述】:

当尝试对返回元组的方法进行单元测试并且我试图查看代码是否访问正确的元组索引时,python 尝试评估预期的调用并将其转换为字符串。

call().methodA().__getitem__(0) 最终被转换为 '().methodA' 在我的expected_calls 断言列表中。

提供的示例代码,结果输出和回溯:

expected_calls=[call().methodA(), '().methodA']
  result_calls=[call().methodA(), call().methodA().__getitem__(0)]
======================================================================
ERROR: test_methodB (badMockCalls.Test_UsingToBeMocked_methods)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\dev\workspace\TestCode\src\badMockCalls.py", line 43, in test_methodB
    self.assertListEqual(expected_calls, self.result_calls)
  File "C:\Python33\lib\unittest\case.py", line 844, in assertListEqual
    self.assertSequenceEqual(list1, list2, msg, seq_type=list)
  File "C:\Python33\lib\unittest\case.py", line 764, in assertSequenceEqual
    if seq1 == seq2:
  File "C:\Python33\lib\unittest\mock.py", line 1927, in __eq__
    first, second = other
ValueError: too many values to unpack (expected 2)

----------------------------------------------------------------------
Ran 1 test in 0.006s

FAILED (errors=1)

如何断言 methodB 正在调用 self.tbm.methodA()[0] 正常吗?

示例代码(Python 3.3.2):

import unittest
from unittest.mock import call, patch
import logging

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
_ch = logging.StreamHandler()
_ch.setLevel(logging.DEBUG)
log.addHandler(_ch)

class ToBeMocked():  # external resource that can't be changed
    def methodA(self):
        return (1,)

class UsingToBeMocked():  # project code
    def __init__(self):
        self.tbm = ToBeMocked()

    def methodB(self):
        value = self.tbm.methodA()[0]
        return value

class Test_UsingToBeMocked_methods(unittest.TestCase):
    def setUp(self):
        self.patcher = patch(__name__ + '.ToBeMocked')
        self.mock_ToBeMocked = self.patcher.start()
        self.utbm = UsingToBeMocked()
        # clear out the mock_calls list from the constructor calls
        self.mock_ToBeMocked.mock_calls = []
        # set result to always point to the mock_calls that we are testing
        self.result_calls = self.mock_ToBeMocked.mock_calls

    def tearDown(self):
        self.patcher.stop()

    def test_methodB(self):
        self.utbm.methodB()
        # make sure the correct sequence of calls is made with correct parameters
        expected_calls = [call().methodA(),
                          call().methodA().__getitem__(0)]
        log.debug('expected_calls=' + str(expected_calls))
        log.debug('  result_calls=' + str(self.result_calls))
        self.assertListEqual(expected_calls, self.result_calls)

if __name__ == "__main__":
    unittest.main()

【问题讨论】:

    标签: python unit-testing python-3.x mocking automated-tests


    【解决方案1】:

    测试mock_object.account['xxx1'].patch(body={'status': 'active'}) 我不得不使用测试:

    mock_object.account.__getitem__.assert_has_calls([
        call('xxxx1'),
        call().patch(body={'status': 'active'}),
    ])
    

    我无法解释为什么会这样,这看起来很奇怪,可能是模拟中的错误,但我一直得到这些结果并且它有效。

    【讨论】:

      【解决方案2】:

      我刚刚偶然发现了同样的问题。我从这里使用了解决方案/解决方法:

      http://www.voidspace.org.uk/python/mock/examples.html#mocking-a-dictionary-with-magicmock

      即:

      >> mock.__getitem__.call_args_list
      [call('a'), call('c'), call('d'), call('b'), call('d')]
      

      您可以跳过魔术函数名称的误解并检查其参数。

      【讨论】:

        猜你喜欢
        • 2010-12-19
        • 1970-01-01
        • 1970-01-01
        • 2015-04-11
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 2019-08-17
        • 2019-12-18
        相关资源
        最近更新 更多