python : mock an attribute or mock the whole class?

标签 python unit-testing mocking

我试图在以下业务代码中模拟 Popen 实例:

process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output = process.communicate()[0]
if process.returncode != 0:

这是我的测试代码设置:

@mock.patch('subprocess.Popen.returncode')
@mock.patch('subprocess.Popen.communicate')
def testCommandExecutesCommunicate(self, mock_popen_communicate, mock_popen_returncode):

我也尝试过:

@mock.patch('subprocess.Popen.returncode')
@mock.patch('subprocess.Popen.communicate')
def testCommandExecutesCommunicate(self, mock_popen_communicate, mock_popen_returncode):

在这两种情况下,我都会收到 returncode 模拟错误

Error
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py", line 329, in run
    testMethod()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1297, in patched
    arg = patching.__enter__()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1369, in __enter__
    original, local = self.get_original()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1343, in get_original
    "%s does not have the attribute %r" % (target, name)
AttributeError: <class 'subprocess.Popen'> does not have the attribute 'returncode'

我应该如何模拟 Popen?我应该以某种方式模拟 Popen 类吗?或者我通过模拟方法+属性走在正确的轨道上吗?

最佳答案

`AttributeError: does not have the attribute 'returncode'

查看subprocess.py中的代码,

class Popen():
    def __init__(self, ....):
        self.returncode = None

属性returncode__init__设置,稍后由communicate()等更新,类属性returncode > 不模拟友好并导致错误

why mockp.communicate() mockp.communicate.return_value = '123'

mockp.communicate 或者配合 (),与 mockp.communicate = mock.Mock() 相同,一种创建方式用于函数communicate

的新模拟对象

mock.communicate.return_value = list([2, 3])是设置mock函数的return_value。

solution: I am not totally happy with the solution, but I tend to think mock the whole class 'Popen()` is the way to go for the unittests.

对于unittest,只需模拟整个类,模拟subprocess.Popen并设置returncodecommunicate()并设置return_value ,例如

remove_file.py

def do_cmd(command):
    process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    exit_code = process.communicate()[0]
    return exit_code

test_remove_file.py

class TestDoCmd(unittest.TestCase):

    @mock.patch('remove_file.subprocess.Popen')
    def test_do_cmd(self, mockp):
        # add function
        mockp.returncode.return_value = 'abc'
        mockp.communicate()
        mockp.communicate.return_value = '123'
        file = '/tmp/none.txt'
        remove_file.do_cmd('rm -f {}'.format(file))
        mockp.assert_called_with('rm -f /tmp/none.txt', shell=True, stdout=-1)

关于 python : mock an attribute or mock the whole class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51562651/

相关文章:

unit-testing - 如何测试永远循环的代码

Java 使用 Mockito 验证 void 方法调用 n 次

php - 为什么 PHPUnit 在模拟不存在的方法时默默地不返回任何内容?

symfony - 如何使用在 Controller 中返回假存储库的模拟实体管理器?

python - python 中机架的拼字游戏单词组合

python - 使用 Pyexcel 处理 Excel 数据

python - 为什么 Online Python Tutor 将这个不可变整数以图形方式呈现为两个不同的整数?

python - Mongo UUID python vs java 格式

c# - 管理员返回 null 但为什么?

c++ - 在编译时使用注释自动包装 C/C++ 函数