我想测试一个类的方法。我想模拟另一个类中的方法。但我总是收到以下错误。
Ran 1 test in 0.005s
FAILED (errors=1)
Error
Traceback (most recent call last):
File "D:\dev\test_unittest\lib\site-packages\mock\mock.py", line 1343, in patched
with self.decoration_helper(patched,
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\contextlib.py", line 119, in __enter__
return next(self.gen)
File "D:\dev\test_unittest\lib\site-packages\mock\mock.py", line 1325, in decoration_helper
arg = exit_stack.enter_context(patching)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\contextlib.py", line 448, in enter_context
result = _cm_type.__enter__(cm)
File "D:\dev\test_unittest\lib\site-packages\mock\mock.py", line 1398, in __enter__
self.target = self.getter()
File "D:\dev\test_unittest\lib\site-packages\mock\mock.py", line 1573, in <lambda>
getter = lambda: _importer(target)
File "D:\dev\test_unittest\lib\site-packages\mock\mock.py", line 1245, in _importer
thing = __import__(import_path)
ModuleNotFoundError: No module named 'foo'
from parentfolder.handler import Handler
class Foo:
def __init__(self):
self.handler = Handler()
def verify_client(self):
client = self.handler.get_value('client')
return client == 'client'
if __name__ == '__main__':
foo = Foo()
re = foo.verify_client()
print(re)
class Handler:
def get_value(self, value):
return value
import unittest
import mock
from parentfolder.foo import Foo
class testFoo(unittest.TestCase):
@mock.patch('foo.Foo.get_value', return_value='client')
def test_verify_client(self):
foo = Foo()
result = foo.verify_client()
self.assertTrue(result)
if __name__ == "__main__":
unittest.main()
您的单元测试代码存在许多问题。
unittest.mock.patch
的文档,您会发现 target
字符串必须采用可从您调用 patch
的环境(即执行单元的环境)导入的形式测试一下。
无法从该环境直接导入名为
foo
的模块,因为该模块位于 parentfolder
包中。因此包名称必须包含在模块路径中,如下所示:patch("parentfolder.foo.[...]")
与您通过在导入路径中提供
Foo
来在 test
模块顶部导入 parentfolder
类的原因相同。
即使您修复了该导入路径,目标字符串的其余部分仍然是错误的,因为
Foo
模块中的 foo
类没有名为 get_value
的属性。这是你的 Handler
类的一个方法。如果你想修补该方法,你需要像这样编写你的目标字符串:patch("parentfolder.foo.Handler.get_value")
请注意,我不需要编写
handler
模块的路径,因为 Handler
类已导入到 foo
模块中,这意味着当 foo
为 时,它将位于 patch
的命名空间中叫。在这种情况下,相当于这样写:patch("parentfolder.handler.Handler.get_value")
使用
patch
作为测试方法的装饰器意味着您必须使用一个附加参数定义它,该参数将由patch
创建的模拟作为参数或您必须向new
提供patch
参数。典型的设置如下所示:
@patch("parentfolder.foo.Handler.get_value")
def test_verify_client(self, mock_get_value):
...
unittest.mock
?这没什么大不了的。这很奇怪,为什么你要安装一个单独的包,因为自从 Python
mock
以来 unittest
已经成为标准库的 3.3
包的一部分。
总而言之,这就是我重写你的
test
模块的方式:
from unittest import TestCase, main
from unittest.mock import MagicMock, patch
from parentfolder.foo import Foo
class FooTestCase(TestCase):
@patch("parentfolder.foo.Handler.get_value")
def test_verify_client(self, mock_get_value: MagicMock) -> None:
mock_get_value.return_value = "client"
foo = Foo()
result = foo.verify_client()
self.assertTrue(result)
if __name__ == "__main__":
main()
patch.object
直接修补其命名空间(无需额外导入),这是可能的,因为模块(就像 Python 中的其他所有东西一样)是一个对象,它的命名空间代表该对象的属性。我认为这是个人喜好的问题:
from unittest import TestCase, main
from unittest.mock import MagicMock, patch
from parentfolder import foo as foo_module
class FooTestCase(TestCase):
@patch.object(foo_module.Handler, "get_value")
def test_verify_client(self, mock_get_value: MagicMock) -> None:
mock_get_value.return_value = "client"
foo = foo_module.Foo()
result = foo.verify_client()
self.assertTrue(result)
if __name__ == "__main__":
main()
我也遇到了类似的问题:对我有用的方法: (检查完以上所有内容后)。 导入系统 sys.path('模块名称')
@patch('module_name.Foo.get_value')