Python的单元测试补丁(unittest patching)无法按预期工作。

3

我有以下的项目结构:

root/
|-mylib/
  |-tests/
  | |-__init__.py
  | |-test_trend.py
  |-__init__.py
  |-data.py
  |-trend.py

trend.py 中:
from mylib.data import get_item

def get_trend(input: str):
    item = get_item(input)
    return f"Trend is: {item}"

data.py 中:

def get_item(id):
    print("ORIGINAL")
    return get_item_from_db(id)

测试

我想要对get_trend进行单元测试,因此我在test_trend.py中对get_item进行了补丁操作:

import unittest
from unittest.mock import patch
from mylib.trend import get_trend

def p__get_item(input):
    return 0

class MyTestCase(unittest.TestCase):
    @patch("mylib.data.get_item", new=p__get_item)
    def test_trend(self):
        v = get_trend()
        self.assertEqual(v, "Trend is: 0")

但是当我运行测试时(该命令在root目录内运行):

python -m unittest discover

我看到日志显示原始的get_item被调用了。 当然测试失败了。
我做错了什么?

尝试1

如果我尝试使用patch API的其他版本

class MyTestCase(unittest.TestCase):
    @patch("mylib.data.get_item")
    def test_trend(self, mocked_fun):
        mocked_fun.return_value = 0
        v = get_trend()
        self.assertEqual(v, "Trend is: 0")

它仍然不能正常工作。在控制台日志中,我可以看到打印了ORIGINAL并且测试失败。

实验1

如果我将@patch中的target更改为不存在的属性,如:

@patch("mylib.data.non_existing", new=p__get_item)

实际上,我从库中得到了一个错误,说该模块不包含这样的属性。因此,看起来mylib.data.get_item已经被正确地定位,但补丁仍未生效。


1
你必须在使用对象的地方打补丁,而不是它来自哪里。由于你在本地导入了它,只需修补 get_stuff。但实际上,你的测试测试的是一个模拟对象,并没有什么帮助。 - Klaus D.
但这就是我正在做的事情。我正在将其补丁到测试文件中,在那里我正在使用它。你能发布一个完整代码的答案吗?我感觉我没有明白你的意思,谢谢。 - Andry
我想知道是否更容易模拟这个函数?另外,也许你是想用new_callable而不是new - LearningNoob
我的例子很简单,只是为了让我知道这个东西是如何工作的。当然,在这个例子中这样做会更容易,但我需要理解如何进行补丁工作...... - Andry
我认为您提交了错误的代码。回溯显示执行的代码与您发布的代码不同。 - xjcl
显示剩余7条评论
1个回答

2

解释

get_item 被调用于 mylib.trend 模块中,但是你在 mylib.data 模块中进行了补丁操作,这是错误的位置。 patch 的作用是替换 import 中的对象。在这种情况下,你需要在 mylib.trend 模块内部修补 get_item,而不是在 mylib.data 中。

解决方案

class MyTestCase(unittest.TestCase):
    @patch("mylib.trend.get_item")
    def test_trend(self, mocked_get_item):
        mocked_get_item.return_value = 0
        ...

备注

关于修补程序应该放在哪里的更多解释,请参阅官方Python文档此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接