【问题标题】:In Python, how can I patch a function from another file that's not imported locally?在 Python 中,如何从另一个未在本地导入的文件中修补函数?
【发布时间】:2023-04-03 15:39:01
【问题描述】:

我正在学习 Pythonic 测试开发,偶然发现了这个看似违反直觉的问题。当我修补与被测代码在同一文件中定义的函数时,patch 可以正常工作。但是当我 import 来自不同文件的函数时,让 patch 正常工作的唯一方法是使 import 成为本地而不是在文件顶部定义它。

最小复制:

a/b.py:

from x.y import z


def c():
    print("In a.b.c")


class D:
    def do_stuff_with_a_b_c(self):
        print("In do_stuff_with_a_b_c")
        c()

    def do_stuff_with_x_y_z(self):
        from x.y import z
        print("In do_stuff_with_x_y_z")
        z()

x/y.py:

def z():
    print("In x.y.z")

测试/d_tests.py:

import inspect
import unittest
from unittest.mock import patch

from x import y
from a.b import D


class DTests(unittest.TestCase):
    def test_do_stuff_with_a_b_c(self):
        print(f"In {inspect.stack()[0][3]}")
        D().do_stuff_with_a_b_c()

    @patch("a.b.c")
    def test_do_stuff_with_patched_a_b_c(self, a_b_c_method):
        print(f"In {inspect.stack()[0][3]}")
        D().do_stuff_with_a_b_c()

    def test_do_stuff_with_x_y_z(self):
        print(f"In {inspect.stack()[0][3]}")
        D().do_stuff_with_x_y_z()

    @patch("x.y.z")
    def test_do_stuff_with_patched_x_y_z(self, x_y_z_method):
        print(f"In {inspect.stack()[0][3]}")
        D().do_stuff_with_x_y_z()

    def test_do_stuff_with_patch_object_x_y_z(self):
        print(f"In {inspect.stack()[0][3]}")
        with patch.object(y, "z"):
            D().do_stuff_with_x_y_z()


if __name__ == '__main__':
    unittest.main()

当我使用上述代码运行测试时,我得到以下输出:

In test_do_stuff_with_a_b_c
In do_stuff_with_a_b_c
In a.b.c
In test_do_stuff_with_patch_object_x_y_z
In do_stuff_with_x_y_z
In test_do_stuff_with_patched_a_b_c
In do_stuff_with_a_b_c
In test_do_stuff_with_patched_x_y_z
In do_stuff_with_x_y_z
In test_do_stuff_with_x_y_z
In do_stuff_with_x_y_z
In x.y.z

但是,当我在 do_stuff_with_x_y_z 中注释掉 x.y.z 的本地导入时,我得到以下输出:

In test_do_stuff_with_a_b_c
In do_stuff_with_a_b_c
In a.b.c
In test_do_stuff_with_patch_object_x_y_z
In do_stuff_with_x_y_z
In x.y.z
In test_do_stuff_with_patched_a_b_c
In do_stuff_with_a_b_c
In test_do_stuff_with_patched_x_y_z
In do_stuff_with_x_y_z
In x.y.z

导致patch 在一种情况下按预期工作但在另一种情况下不能正常工作的两种形式有什么区别?

【问题讨论】:

  • 使用 foo bar Bar baz 和 Buzz 会让人很困惑。

标签:
python
pytest