【问题标题】:How to mock a function in python which is called in the global scope of a module using Pytest?python - 如何在python中模拟一个使用Pytest在模块的全局范围内调用的函数?
【发布时间】:2021-06-26 15:37:39
【问题描述】:

我在“sample.py”中编写了以下函数,在“test_sample.py”中编写了相应的测试脚本。主要功能 roll_dice 在名为“dice.py”的模块中。所有这些文件都在一个名为“myapp”的文件夹中。

场景 1

dice.py

import random
def roll_dice():
    print("rolling...")
    return random.randint(1, 6)

sample.py

from myapp.dice import roll_dice
def guess_number(num):
    result = roll_dice()
    if result == num:
        return "You won!"
    else:
        return "You lost!"

test_sample.py

@mock.patch("myapp.sample.roll_dice")
def test_guess_number(mock_roll_dice):
    mock_roll_dice.return_value = 3
    assert guess_number(3) == "You won!"

当我使用 Pytest 运行测试时,它运行成功。但是当我对如下所示的 sample.py 进行小改动时,测试失败了:

场景 2

sample.py

from myapp.dice import roll_dice
result = roll_dice() # Here is the change
def guess_number(num):
    if result == num:
        return "You won!"
    else:
        return "You lost!"

一切都保持不变!

当我在 sample.py 模块的全局范围内调用它时,测试失败,而不是在另一个函数内部调用函数。谁能告诉我如何模拟场景 2 中的 roll_dice 函数?

我的猜测是我们不能在模块的全局范围内模拟函数调用。对吗?

【问题讨论】:

    标签: python unit-testing testing pytest


    【解决方案1】:

    在场景 2 中,roll_dice 在导入时被调用。 完整的test_sample.py 应该是:

    from myapp.sample import guess_number      # Call to `roll_dice` is done here
                                               # before mock
    
    @mock.patch("myapp.sample.roll_dice")
    def test_guess_number(mock_roll_dice):
        mock_roll_dice.return_value = 3
        assert guess_number(3) == "You won!"
    

    如果你将 import 移到 test 函数中,它也不起作用,因为 patch("myapp.sample.roll_dice") 会在 mocking 之前导入 myapp.sample

    它适用于:

    @mock.patch("myapp.dice.roll_dice")
    def test_guess_number(mock_roll_dice):
        from myapp.sample import guess_number  # Call to `roll_dice` is done here
                                               # You shouldn't have imported `myapp.sample`
                                               # before
        mock_roll_dice.return_value = 3
        assert guess_number(3) == "You won!"
    

    但要小心在导入时执行的代码(全局变量初始化)。最后,您唯一测试的是您对模拟库的了解。

    【讨论】:

      【解决方案2】:

      顺序是

      1. 从 test_sample.py 导入 sample.py
      2. 初始化全局变量result
      3. 从 mock.patch 修补 roll_dice"
      4. 执行测试功能

      当你从test_sample.py导入sample.py时,全局变量result的值会被初始化,但是补丁函数roll_dice需要等到测试夹具初始化。

      results 总是在mock.patching 之前初始化,所以值总是来自原始函数而不是模拟函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-21
        • 2023-01-09
        • 1970-01-01
        • 2022-01-07
        • 2020-04-23
        • 2022-08-03
        • 1970-01-01
        相关资源
        最近更新 更多