从同一软件包中修补一个函数不是修补

发布于 2025-02-01 14:57:57 字数 1286 浏览 3 评论 0原文

我正在使用内置的Unitest库。我正在尝试测试一个函数,在此示例a中,它调用函数b。这两个功能都位于软件包的最高级别,不是基于类的功能。我已经阅读了有关修补何处的Unitest文档,并发现您必须使用该补丁来针对导入其他函数的函数(a)(b),并且不需函数本身(b),但是所有答案和文档似乎仅基于参考类功能。

Heirarchy:顶级

mypkg
|- __init__.py
|- a.py
|- b.py
|- test
  |- __init__.py
  |- test_a.py

__ INT __

from .a import a
from .b import b
__all__ = ['a','b']

import .b import b

def a():
  ...
  functionB({"USERNAME": username, "OTHER": other})

以下

def b(**kwargs):
 // do stuff with kwargs like calling APIs etc
 // This function doesn't return anything

import unittest
from unittest.mock import patch
from ..a import a

fake_return_value = "heythere"

class TestFunctionA(unittest.TestCase):
 @patch('mypkg.a.b', return_value=fake_return_value)
 # @patch('mympkg.b') # Doesn't work, does not override the original function
 def test_mytest(self, mocked_func):
   a()
   mocked_func.assert_called_once_with(stuff)

我 原始功能被调用,而不是模拟功能。

我在这里做错了什么?我不认为单位测试很难,我来自单元测试React应用程序,所以这有点令人沮丧,但我假设用户错误。到目前为止,我所做的所有文档和谷歌搜索似乎都应该起作用,或者至少上面评论了补丁变体。这是因为我的软件包结构并试图在同一软件包中模拟功能还是?

I am using the builtin unittest library. I am trying to test a function,in this example a, which calls function b. Both of these functions are at the top level of the package and are not class based functions. I have read the unittest documentation about where to patch and have found that you must use the patch against the function (a) importing the other function (b)and not patching the function itself (b), but all the answers and documentation seem to only reference class based functions.

I have the following heirarchy:

mypkg
|- __init__.py
|- a.py
|- b.py
|- test
  |- __init__.py
  |- test_a.py

top level __init__.py:

from .a import a
from .b import b
__all__ = ['a','b']

a.py:

import .b import b

def a():
  ...
  functionB({"USERNAME": username, "OTHER": other})

b.py:

def b(**kwargs):
 // do stuff with kwargs like calling APIs etc
 // This function doesn't return anything

test_a.py:

import unittest
from unittest.mock import patch
from ..a import a

fake_return_value = "heythere"

class TestFunctionA(unittest.TestCase):
 @patch('mypkg.a.b', return_value=fake_return_value)
 # @patch('mympkg.b') # Doesn't work, does not override the original function
 def test_mytest(self, mocked_func):
   a()
   mocked_func.assert_called_once_with(stuff)

Running the above tests with the patch call that is uncommented leads to the test being ran and the original function being called, not the mock function.

What am I doing wrong here? I didn't think it would be this hard to unit test, I come from unit testing React apps, so this is a little frustrating but I assume user error. All the documentation and googling I've done so far seems that this should work, or at least the patch variant commented out above. Is this because of my package structure and trying to mock functions in the same package or?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空心↖ 2025-02-08 14:57:57

让我们看一下您的顶级__ init __. py,其中包含在导入时间上执行的代码。

语句来自。 em>函数 a包含在模块a中。因此,导入mypkg.a的所有调用(例如,测试模块中的补丁)将返回 function a而不是模块。这就是为什么您获得错误attributeError:函数A在您的最后一个答案中的评论中没有属性'b'

要修补模块a的函数用法b,您的测试代码需要能够导入模块a。有几种方法可以做到这一点。

  • 从.a __ init __. py 中删除.a导入。
    • 您仍然可以从mypkg导入或导入mypkg.a a a a li>
    • 您仍然可以通过mypkg..a导入或导入mypkg.aa a a a
  • 重命名函数 a对其他东西。

Let's look at your top level __init__.py which contains code executed at import time.

The statement from .a import a rebinds the name a from the module a, to the function a contained within module a. As such, all invocations of import mypkg.a (e.g. the patch in your test module) will return the function a and not the module. That is why you get the error AttributeError: function a does not have the attribute 'b' mentioned in your comment on my last answer.

To patch module a's usage of function b, your testing code needs to be able to import module a. There are a few ways you can do this.

  • Remove from .a import a in your __init__.py.
    • You can still access the module a via from mypkg import a or import mypkg.a
    • You can still access the function a via from mypkg.a import a or import mypkg.a.a
  • Rename the function a to something else.
无名指的心愿 2025-02-08 14:57:57

注意:此答案地址为a 上一个修订版问题的问题

已注释的patch确实是正确的一个要使用的一种,因为您正在尝试修补b的引用。 b是类还是一个函数,这并不重要,因为像JavaScript一样,两个都是python中的一流对象,并通过unittest.mock.patch < /代码>以相同的方式。

我怀疑您更复杂的系统中的问题与示例中的以下错误之一有关:

  • 补丁应从UnitTest.mock导入import fatch 将其导入为
  • 模拟的return_value应在您的测试中,而不是在装饰器中分配。
  • 东西不在测试类的范围内。

工作,等效的示例

这是您描述的系统的工作示例:

  • 两个模块, a 和b,每个模块都带有顶级功能
  • 模块ab调用功能。
  • 您想在b中修补该函数以隔离测试模块a

文件层次结构:

mypkg
|- __init__.py    // empty
|- a.py
|- b.py
|- test
  |- __init__.py  // empty
  |- test_a.py

b.py

def b():
  return "World!"

a.py

from .b import b

def a():
  return "Hello " + b()

test_a.py

import unittest
from unittest.mock import patch
from ..a import a

class TestFunctionA(unittest.TestCase):
    def test_a_no_mock(self):
        message = a()
        self.assertEqual(message, "Hello World!")

    @patch('mypkg.a.b')
    def test_mytest(self, mocked_func):
        mocked_func.return_value = "Stack Overflow!"
        message = a()
        self.assertEqual(message, "Hello Stack Overflow!")
        mocked_func.assert_called_once()

从文件夹中运行包含 的测试mypkg

$ ls
mypkg
$ python -m unittest discover
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

NOTE: This answer addresses a previous revision of the question

The commented out patch is indeed the correct one to use since you are trying to patch a's reference to b. It doesn't really matter if b is a class or a function since, like JavaScript, both are first-class objects in Python and are looked up and patched by unittest.mock.patch in the same way.

I suspect the issue in your more complex system has to do with one of the following errors in your example:

  • patch should be imported as from unittest.mock import patch.
  • The mocked return_value should be assigned within your test, not within the decorator.
  • stuff isn't in the scope of your test class.

Working, Equivalent Example

Here's a working example of the system you describe:

  • Two modules, a and b, each with a top-level function
  • Module a invokes a function from b.
  • You want to patch the function in b to test module a in isolation.

File Hierarchy:

mypkg
|- __init__.py    // empty
|- a.py
|- b.py
|- test
  |- __init__.py  // empty
  |- test_a.py

b.py

def b():
  return "World!"

a.py

from .b import b

def a():
  return "Hello " + b()

test_a.py

import unittest
from unittest.mock import patch
from ..a import a

class TestFunctionA(unittest.TestCase):
    def test_a_no_mock(self):
        message = a()
        self.assertEqual(message, "Hello World!")

    @patch('mypkg.a.b')
    def test_mytest(self, mocked_func):
        mocked_func.return_value = "Stack Overflow!"
        message = a()
        self.assertEqual(message, "Hello Stack Overflow!")
        mocked_func.assert_called_once()

Running the tests from the folder containing mypkg

$ ls
mypkg
$ python -m unittest discover
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文