繁体   English   中英

python单元测试模拟Popen和Popen.communicate

[英]python unit testing mocking Popen and Popen.communicate

我正在尝试编写一个执行子流程调用的python unittest,所以我想模拟该调用。

我已经经历了这些SO问题(无济于事):

benchmark.py

from subprocess import Popen, PIPE, STDOUT

def some_func():

  with Popen(some_list, stdout=PIPE, stderr=STDOUT) as process:

    stdout, stderr = process.communicate(timeout=timeout)

test.py

import mock

@mock.patch('benchmark.Popen.communicate')
@mock.patch('benchmark.Popen')
def test_some_func(self, mock_popen, mock_comm):

  mock_popen.return_value = 0
  mock_comm.return_value = ('output', 'error')

  foo = benchmark.some_func()

运行单元测试时,我得到:

    stdout, stderr  = process.communicate(timeout=timeout)
ValueError: not enough values to unpack (expected 2, got 0)

看来我没有嘲笑正确communicate的返回值; 我究竟做错了什么?

我接受了评论并提出了解决此类问题的答案:

test.py

import mock

@mock.patch('benchmark.Popen')
def test_some_func(self, mock_popen):

  process = mock_popen.return_value.__enter__.return_value
  process.returncode = 0
  process.communicate.return_value = (b'some output', b'some error')

  foo = benchmark.some_func()

正如jonrsharpe已经提到的, with Popen(...) as process使用Popen实例作为上下文管理器,它调用__enter__方法并分配它的值process

jonsharpe的解决方案使用了mock return_value魔术,效果很好。 但是您也可以实现一个上下文管理器,并将模拟逻辑包装在其中:

import mock
import subprocess


class MockedPopen:

    def __init__(self, args, **kwargs):
        self.args = args
        self.returncode = 0

    def __enter__(self):
        return self

    def __exit__(self, exc_type, value, traceback):
        pass

    def communicate(self, input=None, timeout=None):
        if self.args[0] == 'ls':
            stdout = '\n'.join(['hello.txt', 'world.txt'])
            stderr = ''
            self.returncode = 0
        else:
            stdout = ''
            stderr = 'unknown command'
            self.returncode = 1

        return stdout, stderr


@mock.patch('subprocess.Popen', MockedPopen)
def foo():
    with subprocess.Popen(['ls']) as proc:
        stdout, stderr = proc.communicate()
        print(stdout, stderr)


foo()

输出:

hello.txt
world.txt

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM