python - hamcrest.contains_inanyorder 的几乎无用的断言输出应用于 unittest.mock.Mock.mock_calls

标签 python python-3.x hamcrest python-unittest.mock

通常,我关心被测系统对软件的另一部分(我在测试中模拟的)进行的确切调用,但不关心这些调用发生的顺序。 (例如,因为被模拟替换的真实其他部分的最终效果不取决于这些调用的顺序。)

换句话说,我希望我的测试

  • 如果未完成所有预期调用,则失败
  • 如果发生意外调用,则会失败(因此 unittest.mock.Mock.assert_has_calls 不够)
  • 如果仅调用的顺序发生变化,不会失败
  • 如果调用次数少于或高于预期,则失败

所以,我必须检查 mock_calls property模拟对象的。我可以使用 PyHamcrest 的 contains_inanyorder 以通用且合理理解的方式做到这一点:

#!/usr/bin/env python3
from unittest import TestCase, main
from unittest.mock import Mock, call
from hamcrest import assert_that, contains_inanyorder as contains_in_any_order

class TestMockCalls(TestCase):
    def test_multiple_calls(self):
        m = Mock()
        m('foo')
        m.bar('baz')
        m('foo')
        assert_that(
            m.mock_calls, contains_in_any_order(
                call('foo'),
                call('foo'),
                call.bar('baz'),
            )
        )

if __name__ == '__main__':
    main()

这对于通过测试很有效,就像上面的测试一样:

$> ./test_mock_calls.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

当它应该失败时它也会失败(如上所述,例如,当您将 m('foo') 之一更改为 m('F00') 时) ,但这种情况下的输出并没有想象中那么有用:

$> ./test_mock_calls.py
F
======================================================================
FAIL: test_multiple_calls (__main__.TestMockCalls)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test_mock_calls.py", line 16, in test_multiple_calls
    call.bar('bay'),
AssertionError: 
Expected: a sequence over [, , ] in any order
     but: not matched: 


----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

我可以从中收集到的唯一信息(除了哪个测试和哪个断言失败之外)是总共预期对模拟进行多少次调用(通过计算方括号之间的逗号),而不是预期的调用次数更重要的是,实际观察到的调用内容和数量。

这是 unittest.mock 或 PyHamcrest 中的错误还是我使用它们错误?

最佳答案

问题在于 call (_Call) 本身是一种模拟,并覆盖 __getattr__。当 hamcrest 开始检查它是​​否具有 describe_to 属性时,事情开始出错。

我认为,由于两个模块都在做内省(introspection)的事情,所以没有一个应该受到责备,并且应该在任一方实现特殊情况,以便与另一方很好地配合(可能在 hamcrest 中,因为 mock是一个标准模块)。

用户端解决方法是:

from unittest.mock import _Call
_Call.describe_to = lambda c, d: d.append(str(c))

关于python - hamcrest.contains_inanyorder 的几乎无用的断言输出应用于 unittest.mock.Mock.mock_calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36967375/

相关文章:

python - Pandas - 处理分类数据中的 NaN

string - 寻找改进我的刽子手代码的方法

scala - 规范 2:使用 Hamcrest 匹配器

java - 如何使用 jsonpath 和 hamcrest 断言 json 属性大于 0?

python - 矩形之间的曼哈顿距离

python - 如何在不阻塞的情况下发出请求(使用 asyncio)?

涉及 HTML a 标签的 Python 网络抓取

python - 用 python/biopython 计算 DNA 序列

python-3.x - 使用 periodIndex 列中的数据创建新列

junit - 测试 Java 6 和 Java 8 中的类型匹配差异