unittest 将命名空间列入黑名单,并失败任何引用它的尝试



在对包装库进行单元测试的情况下,在不依赖/执行上游库的情况下测试包装器是一个目标;在已知的情况下,所有对上游库的调用都可以被模拟,这就是我所做的,但我对包装器的更改感到沮丧,这些更改引入了更多对上游库的调用,而模拟工具错过了这些调用;

如何才能最好地使尝试使用给定命名空间的任何测试失败?

我目前的想法是更改所有 unittest 方法以拥有像猴子补丁这样的猴子补丁

@unittest.mock.patch('wrapper_namespace.upsteam_namespace')

并用可以原封不动地断言的模拟回复上游库;我希望有一个在全球范围内有效的选项,以便我

不必为每个测试方法
  • 添加一个 monkeypatch,尽管这种级别的粒度是可以接受的;但也不必断言模拟从未在测试方法中使用过(或制作一个装饰器来做所有这些事情(
  • 禁止从软件的任何部分访问上游库 (例如,包装器调用 B 调用上游,B 对上游的调用可能不会被捕获(

您不必修补每个测试方法。如果您使用的是unittest,则可以轻松地修补class,或者只是将模块分配给您想要修补的任何内容。下面是一个可行的示例:

some_lib.py中的假库:

def some_lib_func():
raise ValueError("I've been called.")
def some_other_lib_func():
raise ValueError("I've been called.")
class SomeClass:
def __init__(self):
raise ValueError("I've been constructed.")

wrapper.py:

import some_lib
def wrapper1():
some_lib.some_lib_func()
def wrapper2():
some_lib.some_other_lib_func()
def wrapper3():
x = some_lib.SomeClass()

test.py:

from unittest.mock import patch, MagicMock
import unittest
import wrapper
# Alternative:                                                                                                                                            
# wrapper.some_lib = MagicMock()                                                                                                                                                                            
# Can patch an entire class                                                                                                                                                                                 
@patch('wrapper.some_lib', MagicMock())
class TestWrapper(unittest.TestCase):
def test_wrapper1(self):
wrapper.wrapper1()
def test_wrapper2(self):
wrapper.wrapper2()
def test_wrapper3(self):
wrapper.wrapper3()
if __name__ == "__main__":
unittest.main()

如果调用some_lib中的函数/类,我们会爆炸,但它们不是:

Matthews-MacBook-Pro:stackoverflow matt$ python test.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK

随意注释掉补丁并在wrapper.some_lib = MagicMock()中发表评论。在这个玩具示例中,你会得到相同的结果,但这两种方法之间存在重大差异:

使用@patch('wrapper.some_lib', MagicMock())补丁仅对该测试用例类有效。

但是,当使用wrapper.some_lib = MagicMock(),该补丁将在整个python程序的整个长度上保持活动状态,除非您保存原始模块并在某个时候手动修补它。所有使用wrapper模块的内容都将获得模拟版本。

所以你可以这样:

original_lib = wrapper.some_lib
wrapper.some_lib = MagicMock()
...
# call some test suite, every call to the wrapper module will be mocked out
...
wrapper.some_lib = original_lib
...
# call some other test suite that actually needs the real thing
...

呵呵。

编辑:稍微误读了你的问题,但你可以检查MagicMock对象,看看它们是否被调用,如果是,测试失败。或者只是修补一些在调用时失败的东西(而不是MagicMock(。如果需要,我可以提供代码来执行此操作(只需发表评论(,但希望上述内容可以帮助您入门。我认为问题的关键在于全局修补。干杯!

最新更新