我遇到了以下情况(边缘?),我不知道如何正确处理。普遍的问题是
这是我的代码库中的简化示例:
import itertools
import random
def my_side_effects():
# imaginge itertools.accumulate was some expensive strange function
# that consumes an iterable
itertools.accumulate(random.randint(1, 5) for _ in range(10))
def test_my_side_effects(mocker):
my_mocked_func = mocker.patch('itertools.accumulate')
my_side_effects()
# make sure that side-effects took place. can't do much else.
assert my_mocked_func.call_count == 1
该测试运行得很好,足以满足我的所有需求。但是当我运行coverage
代码时,我在摘要中描述的情况就显而易见了:
----------- coverage: platform linux, python 3.8.0-final-0 -----------
Name Stmts Miss Branch BrPart Cover Missing
----------------------------------------------------------------------------------
[...]
my_test_case.py 5 0 2 1 86% 6->exit
[...]
----------------------------------------------------------------------------------
# something like this, the ->exit part on the external call is the relevant part
->exit
coverage.py中语法的说明。鉴于理解能力可以执行我实际上确实想运行的相关业务逻辑,因此错过的覆盖范围很重要。它只是random.randint
在这里打电话,但它可以做任何事情。
解决方法:
monkeypatch.setattr('itertools.accumulate', lambda x: [*x])
描述。但是我将失去像我的示例那样做出呼叫断言的能力。我认为一个好的解决方案是这样的,但遗憾的是不存在:
def test_my_side_effects(mocker):
my_mocked_func = mocker.patch('itertools.accumulate')
# could also take "await", and assign treatments by keyword
my_mocked_func.arg_treatment('unroll')
my_side_effects()
# make sure that side-effects took place. can't do much else.
assert my_mocked_func.call_count == 1
您是正确的,这里缺少覆盖范围:实际上,由于从未使用过累加器,因此您甚至可以:
itertools.accumulate(ERRORERRORERROR for _ in range(10))
而且您现有的测试仍会通过(明显的错误刚刚被模拟)。
要解决此问题,请使用side_effect
的模拟:
my_mocked_func = mocker.patch('itertools.accumulate', side_effect=list)
当使用可调用对象作为模拟对象时side_effect
,它会使用与该模拟对象相同的参数进行调用,并且该可调用对象的返回值将用作该模拟对象的返回值(注意:这意味着您还可以在此处声明返回值而不是直言不讳的call_count
断言)。
这将使您能够消耗发电机并在此处获得100%的覆盖率。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句