Python unittest 模拟类和类方法 [英] Python unittest mock class and class method
问题描述
我觉得这可能相对简单,但我正在努力使其工作.我想模拟整个类,然后指定此类方法之一的返回值.
I feel like this may be relatively simple, but I'm pulling my hair out to get this working. I'd like to mock an entire class, and then specify the return value for one of this class's methods.
我已经看过这里,还有其他几个问题,当然还有 docs.我仍然无法让它发挥作用.请看我下面的简单例子.
I already looked here, at several other questions, and of course in the docs. I'm still unable to get this to work. Please see my simple example below.
目录tmp
的内容:
tmp
├── __init__.py
├── my_module.py
└── test_my_module.py
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
test_my_module.py
的内容:
import unittest
from unittest.mock import patch, Mock
from tmp import my_module
class MyClassTestCase(unittest.TestCase):
def test_create_class_call_method(self):
# Attempt to patch MyClass as well as specify a return_value for
# the my_method method (spoiler: this doesn't work)
with patch('tmp.my_module.MyClass',
my_method=Mock(return_value=2)):
value = my_module.create_class_call_method()
self.assertEqual(value, 2)
if __name__ == '__main__':
unittest.main()
运行test_my_module.py
的结果:
2 != <MagicMock name='MyClass().my_method()' id='140234477124048'>
Expected :<MagicMock name='MyClass().my_method()' id='140234477124048'>
Actual :2
我尝试过的其他一些事情:
Some other things I've tried:
- 而不是
..., 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)
- 使用补丁装饰器代替上下文管理器
- 将 patch 语句更改为
with patch('tmp.my_module.MyClass') as p:
然后在with
语句中,尝试设置p
像这样:p.evaluate = Mock(return_value=2)
- Rather than
..., my_method=Mock(return_value=2))
in thepatch
statement, unpack a dictionary like so:**{'my_method.return_value': 2}
- Nested
with patch
statements. Outer statement is simple likewith patch('tmp.my_module.MyClass'):
, inner statement attempts to patchmy_method
like so:with patch('tmp.my_module.MyClass.my_method, return_value=2)
- Use patch decorators instead of context managers
- Change patch statement to
with patch('tmp.my_module.MyClass') as p:
and then inside thewith
statement, try to setp
like so:p.evaluate = Mock(return_value=2)
感谢任何帮助,谢谢.
推荐答案
我找到了一个更好的解决方案.简而言之,我们需要模拟 MyClass
模拟的 return_value
.这是工作测试代码:
I've found a much better solution. In short, we need to mock out the return_value
of the MyClass
mock. Here's the working test code:
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()
以及成功的结果:
Ran 1 test in 0.002s
OK
这篇关于Python unittest 模拟类和类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!