我正在使用mock
和py.test
进行单元测试。
正在测试的一项功能如下所示:
def convert(rows):
rows = (preprocess(r) for r in rows)
return batch_process(True, rows)
在测试中,我会模仿preprocess
和batch_process
。
对于preprocess
,我使用side_effect
配置多个返回值,每个行一个。
如何断言传递给batch_process
的第二个参数是preprocess
行的生成器表达式?
答案 0 :(得分:2)
考虑简化测试:您需要测试的是,作为生成器遍历的第二个参数包含preprocess()
为每行返回的值。
我将简要介绍如何最终编写它:
from mock import Mock, call
preprocess_sentinels = [Mock() for _ in range(5)]
mock_preprocess.side_effect = preprocess_sentinels
rows = [Mock() for _ in range(5)]
convert(rows)
mock_preprocess.assert_has_calls([call(r) for r in rows])
args, kwargs = mock_batch_process.call_args
assert args[0]
for v, e in zip(args[1], preprocess_sentinels):
assert v == e
当然,以这种方式你不严格检查它是一个生成器,但你检查convert()
行为。确切地检查你是如何实现它的(通过生成器或列表)不是测试应该做的,它是一个实现细节而不是行为:你应该编写适用于这两种情况的最佳测试。
答案 1 :(得分:0)
我找到了一种检查方法,但这有点冗长,但是在我的项目中对我有用
from mock import Mock, patch
from types import GeneratorType
def test():
mock_batch_process = patch('module.calling.batch_process')
mock_preprocess = patch('module.calling.preprocess')
# our test data for rows
rows = ...
convert(rows)
assert mock_batch_process.call_count == 1
args, kwargs = mock_batch_process.call_args
# get an arg that is expected to be a generator, second arg in this case
preprocess_rows = args[1]
# check that our call arg is a generator
assert isinstance(preprocess_rows, GeneratorType)
# check that it contains all expected values
assert list(preprocess_rows) == [mock_preprocess(row) for row in rows]