Python mock/unittest:你如何嘲笑class成员?

Python mock/unittest: How do you mock a class member?

我正在尝试对一个脚本进行单元测试,该脚本读取 requirements.txt 文件并通过 pip 安装它的每一行。然而,我的单元测试似乎没有进入循环,因为 self.requirements 是空的。我尝试将其设置为 self.setupvirtualenv.requirements 到 ['foobar'] 但这不起作用。

我的问题是如何模拟 self.requirements 列表,使其进入 for 循环并调用 subprocess.call?

def install_requirements(self):
    self.requirements = open(self.requirements_path, 'r').readlines()
    for req in self.requirements:
        req = req.strip()
        pip_command = r'pip install {}'.format(req)
        subprocess.call(pip_command, shell=True)

我的单元测试:

import setupvirualenv
import unittest
from mock import patch, Mock

def test_install_requirements(self, mock_open, mock_subprocess_call):
    self.setupvirtualenv.requirements = ['foobar']
    self.setupvirtualenv.install_requirements()
    mock_open.assert_called_once_with('foobar', 'r')
    mock_subprocess_call.assert_called_once() 

失败信息

AssertionError: Expected 'call' to have been called once. Called 0 times.

您应该模拟 open 调用,以便 readlines() returns 虚拟数据。

看起来您可能缺少测试方法中的 patch 装饰器。我在下面列出了它们的外观。

from mock import patch

@patch('setupvirtualenv.subprocess.call')
@patch('setupvirtualenv.open')
def test_install_requirements(self, mock_open, mock_subprocess_call):
    # Mock the call to open() and the return value from readlines()
    mock_open.return_value.readlines.return_value = ['foobar\n']
    self.setupvirtualenv.install_requirements()
    mock_open.assert_called_once_with('foobar', 'r')
    mock_subprocess_call.assert_called_once()