模拟subprocess.check_call不止一次

时间:2018-10-17 20:29:28

标签: python unit-testing mocking python-unittest

我有一个调用subprocess.check_call()两次的函数。我想测试所有可能的输出。我希望能够将第一个check_call()设置为返回1,第二个设置为返回0,并针对所有可能的组合进行设置。以下是我到目前为止的内容。我不确定如何调整期望的返回值

@patch('subprocess.check_call')
def test_hdfs_dir_func(mock_check_call):
    for p, d in list(itertools.product([1, 0], repeat=2)):
        if p or d:

1 个答案:

答案 0 :(得分:1)

您可以将模拟的side_effect分配给可迭代对象,并且每次调用时都会返回可迭代对象中的下一个值。在这种情况下,您可以执行以下操作:

import copy
import itertools
import subprocess

from unittest.mock import patch

@patch('subprocess.check_call')
def test_hdfs_dir_func(mock_check_call):
    return_values = itertools.product([0, 1], repeat=2)
    # Flatten the list; only one return value per call
    mock_check_call.side_effect = itertools.chain.from_iterable(copy.copy(return_values))
    for p, d in return_values:
        assert p == subprocess.check_call()
        assert d == subprocess.check_call()

请注意以下几点:

  • 我没有您的原始功能,因此我将自己的调用放在循环中check_call上。
  • 我在原始itertools.product返回值上使用copy,因为如果我不这样做,它将使用原始迭代器。当我们需要两个单独的列表时,这将耗尽原始的迭代器:一个用于模拟的side_effect,另一个用于您在测试中循环通过。
  • 您可以使用side_effect做其他整洁的事情,而不仅仅是提高。如上所示,您可以更改多个调用的返回值:https://docs.python.org/3/library/unittest.mock-examples.html#side-effect-functions-and-iterables
    • 不仅如此,您还可以从上面的链接中看到它也可以为它提供一个函数指针。这样,在跟踪多个模拟调用时,您甚至可以执行更复杂的逻辑。