如何断言使用生成器调用mock函数?

时间:2016-02-25 03:18:02

标签: python unit-testing mocking

我正在使用mockpy.test进行单元测试。

正在测试的一项功能如下所示:

def convert(rows):
    rows = (preprocess(r) for r in rows)
    return batch_process(True, rows)

在测试中,我会模仿preprocessbatch_process。 对于preprocess,我使用side_effect配置多个返回值,每个行一个。

如何断言传递给batch_process的第二个参数是preprocess行的生成器表达式?

2 个答案:

答案 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]