blt*_*yer 6 python unit-testing mocking python-3.x python-unittest
我觉得这可能相对简单,但我正在拉我的头发以使其工作。我想模拟整个类,然后指定此类方法之一的返回值。
我已经看过了这里,还有其他几个问题,当然还有docs。我仍然无法让它发挥作用。请看我下面的简单例子。
目录内容tmp:
tmp
??? __init__.py
??? my_module.py
??? test_my_module.py
Run Code Online (Sandbox Code Playgroud)
内容my_module.py:
tmp
??? __init__.py
??? my_module.py
??? test_my_module.py
Run Code Online (Sandbox Code Playgroud)
内容test_my_module.py:
class MyClass:
def __init__(self):
# Do expensive operations that will be mocked in testing.
self.a = 7
def my_method(self):
# For sake of simple example, always return 1.
return 1
def create_class_call_method():
"""Create MyClass instance and call its my_method method, returning
the result."""
instance = MyClass()
value = instance.my_method()
return value
Run Code Online (Sandbox Code Playgroud)
运行结果test_my_module.py:
2 != <MagicMock name='MyClass().my_method()' id='140234477124048'>
Expected :<MagicMock name='MyClass().my_method()' id='140234477124048'>
Actual :2
Run Code Online (Sandbox Code Playgroud)
我尝试过的其他一些事情:
..., my_method=Mock(return_value=2))在patch语句中,像这样解压字典:**{'my_method.return_value': 2}with patch语句。外部语句很简单with patch('tmp.my_module.MyClass'):,内部语句尝试my_method像这样修补:with patch('tmp.my_module.MyClass.my_method, return_value=2)with patch('tmp.my_module.MyClass') as p:然后在with语句内部,尝试设置p如下:p.evaluate = Mock(return_value=2)任何帮助表示赞赏,谢谢。
我不确定 的实现create_class_call_method,但请尝试以下操作:
from unittest import mock
class MyClassTestCase(unittest.TestCase):
@mock.patch('tmp.my_module.MyClass.my_method')
@mock.patch('tmp.my_module.MyClass.__init__')
def test_create_class_call_method(self, my_class_init, my_method_mock):
my_class_init.return_value = None
my_method.return_value = 2
value = my_module.create_class_call_method()
self.assertEqual(value, 2)
Run Code Online (Sandbox Code Playgroud)
我找到了一个更好的解决方案。总之,我们需要模拟出return_value的的MyClass模拟。这是工作测试代码:
import unittest
from unittest.mock import patch, Mock, MagicMock
from tmp import my_module
class MyClassTestCase(unittest.TestCase):
def test_create_class_call_method(self):
# Create a mock to return for MyClass.
m = MagicMock()
# Patch my_method's return value.
m.my_method = Mock(return_value=2)
# Patch MyClass. Here, we could use autospec=True for more
# complex classes.
with patch('tmp.my_module.MyClass', return_value=m) as p:
value = my_module.create_class_call_method()
# Method should be called once.
p.assert_called_once()
# In the original my_method, we would get a return value of 1.
# However, if we successfully patched it, we'll get a return
# value of 2.
self.assertEqual(value, 2)
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
以及成功的结果:
Ran 1 test in 0.002s
OK
Run Code Online (Sandbox Code Playgroud)
我认为正确的方法可以在这个答案中找到
注意:下面是一个草图 - 可能无法正确理解 OP 的所有细节
import unittest
from unittest.mock import patch
from tmp import my_module
class MyClassTestCase(unittest.TestCase):
@patch('tmp.my_module.MyClass')
def test_create_class_call_method(self, my_class_mock):
my_class_mock.return_value.my_method.return_value = 2
value = my_module.create_class_call_method()
self.assertEqual(value, 2)
Run Code Online (Sandbox Code Playgroud)