【问题标题】:Pytest mock global variable in subprocess.call()subprocess.call() 中的 Pytest 模拟全局变量
【发布时间】:2019-04-07 08:46:00
【问题描述】:

these answers 之后可以轻松地模拟全局变量。伟大的。但是,当尝试在 Pytest 测试中模拟您使用 subprocess.call() 调用的脚本中的变量时,这不起作用。

这是我在名为so_script.py 的文件中的简化脚本:

import argparse

INCREMENTOR = 4


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('input_nr', type=int, help='An int to increment')
    args = parser.parse_args()

    with open('test.txt', 'w+') as f:
        f.write(str(args.input_nr + INCREMENTOR))

现在,假设我想在我的测试中将 INCREMENTOR 的值模拟为 1。如果我这样做:

from subprocess import call
from unittest import mock

def test_increments_with_1():
    with mock.patch('so_script.INCREMENTOR', 1):
        call(['python', 'so_script.py', '3'])
    with open('test.txt', 'r+') as f:
        assert f.read() == '4'

测试将失败,因为 INCREMENTOR 的值仍然是 4,即使我尝试将其修补为 1。所以写入文件的内容是 7 而不是 4。

所以我的问题是:如何在我的 so_script.py 文件中模拟 INCREMENTOR 全局变量,以便在对其调用 subprocess.call() 时保持模拟状态?

【问题讨论】:

  • Mock 与语言资源(对象)一起使用。在这种情况下,您正在使用操作系统资源。当您从 so 调用子进程时,根据定义,您不是在使用 Python 资源,而是使用 so 资源并将结果(有时是标准输出)分配给 Python 对象。这就是为什么你不能做你想做的事。

标签: python unit-testing mocking pytest patch


【解决方案1】:

因为so_script.py 脚本和pytest 在不同的进程中执行,所以不能模拟so_script.py 中的对象,而后者在测试中被称为不同的进程。

我找到的最佳解决方案是将 if __name__ == '__main__: 块中的所有内容放入一个函数中,并使用 Pytest 测试该函数,模拟我需要模拟的任何内容。而且,为了获得 100% 的测试覆盖率(这是我将脚本作为子进程调用的最初意图),我申请了 this solution

所以我在测试中放弃使用subprocess.call() 并编写了一个init() 函数检查if __name__ == '__main__:,然后在测试中模拟__name__ 以测试该函数,正如文章建议的那样。这让我获得了 100% 的测试覆盖率和完整的模拟功能。

【讨论】:

    猜你喜欢
    • 2022-08-03
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 2022-12-21
    • 2023-01-09
    • 2017-03-19
    相关资源
    最近更新 更多