模拟 subprocess.Popen 而不执行

Mocking subprocess.Popen without executing

我正在尝试为调用 subprocess.Popen 的方法编写单元测试。我想要测试的是发送到 Popenarg 参数是否符合预期。我实际上并不想要 Popen 到 运行。如果不模拟 arg 列表,这可能吗?

例如

def call_something(argument_list):
    binary = '/opt/mybin/'
    Popen([binary] + argument_list)

然后,进行测试。

@mock.patch('subprocess.Popen')
def test_call_something(self, mock_popen):
    binary = '/opt/mybin/'
    args = ['foo', 'bar']

    mock_popen.return_value.returncode = 0
    mock_popen.return_value.communicate.return_value = ('Running', '')

    call_something(args)

    self.assertEqual(
        [binary] + args,
        mock_popen.call_args_list
    )

我遇到的问题是,首先二进制文件被调用(我不想要),其次,call_args_list 是空的。

使用mock.patch时必须指向导入的对象

参见 documentation and this article 解释得很好。


例如,在您的情况下:

code.py

from subprocess import Popen

def call_something(argument_list):
    binary = '/opt/mybin/'
    Popen([binary] + argument_list)

test.py(假设两个文件都在同一个文件夹中,你需要在测试中修补 code.Popen 而不是 subprocess.Popen

from code import call_something

@mock.patch('code.Popen')
def test_call_something(self, mock_popen):
   binary = '/opt/mybin/'
   args = ['foo', 'bar']
   mock_popen.return_value.returncode = 0
   mock_popen.return_value.communicate.return_value = ('Running', '')

   call_something(args)

self.assertEqual(
    [binary] + args,
    mock_popen.call_args_list
)