我有一个python 2.7x Tornado应用程序,运行时提供一些RESTful api端点.
我的项目文件夹包含许多依赖python mock模块的测试用例,如下所示.
from tornado.testing import AsyncHTTPTestCase
from mock import Mock, patch
import json
from my_project import my_model
class APITestCases(AsyncHTTPTestCase):
def setUp(self):
pass
def tearDown(self):
pass
@patch('my_project.my_model.my_method')
def test_something(
self,
mock_my_method
):
response = self.fetch(
path='http://localhost/my_service/my_endpoint',
method='POST',
headers={'Content-Type': 'application/json'},
body=json.dumps({'hello':'world'})
)
Run Code Online (Sandbox Code Playgroud)
RESTful端点分别http://localhost/my_service/my_endpoint有两个内部调用my_method:my_method(my_arg=1)和my_method(my_arg=2).
我想my_method在这个测试用例中模拟出来,0如果用my_arg== 2 调用它会返回,否则它应该返回它通常会返回的内容.我该怎么做?
我知道我应该这样做:
mock_my_method.return_value = SOMETHING
Run Code Online (Sandbox Code Playgroud)
但是我不知道如何正确地指定某些东西,以便它的行为是以调用my_method的参数为条件的.有人可以给我看看还是给我一个例子?
my_method我想在这个测试用例中进行模拟,如果使用 调用它,它会返回 0my_arg==2,但否则它应该返回通常总是返回的内容。我该怎么做?
编写您自己的方法,根据条件模拟调用原始方法:
from my_project import my_model
my_method_orig = my_project.my_model.my_method
def my_method_mocked(self, *args, my_arg=1, **kwargs):
if my_arg == 2: # fake call
return 0
# otherwise, dispatch to real method
return my_method_orig(self, *args, **kwargs, my_arg=my_arg)
Run Code Online (Sandbox Code Playgroud)
对于修补:如果您不需要断言模拟方法的调用频率以及参数等,那么通过new参数传递模拟就足够了:
@patch('my_project.my_model.my_method', new=my_method_mocked)
def test_something(
self,
mock_my_method
):
response = self.fetch(...)
# this will not work here:
mock_my_method.assert_called_with(2)
Run Code Online (Sandbox Code Playgroud)
如果您想调用整个模拟断言机制,请side_effect按照其他答案中的建议使用。例子:
@patch('my_project.my_model.my_method', side_effect=my_method_mocked, autospec=True)
def test_something(
self,
mock_my_method
):
response = self.fetch(...)
# mock is assertable here
mock_my_method.assert_called_with(2)
Run Code Online (Sandbox Code Playgroud)
您可以使用side_effect动态更改返回值:
class C:
def foo(self):
pass
def drive():
o = C()
print(o.foo(my_arg=1))
print(o.foo(my_arg=2))
def mocked_foo(*args, **kwargs):
if kwargs.get('my_arg') == 2:
return 0
else:
return 1
@patch('__main__.C.foo')
def test(mock):
mock.side_effect = mocked_foo
drive()
Run Code Online (Sandbox Code Playgroud)
更新:当你想my_method在某种情况下运行原始代码时,你可能需要一个方法代理,Mock无法取回正在修补的真实函数对象。
from unittest.mock import patch
class MyClass:
def my_method(self, my_arg):
return 10000
def func_wrapper(func):
def wrapped(*args, **kwargs):
my_arg = kwargs.get('my_arg')
if my_arg == 2:
return 0
return func(*args, **kwargs)
return wrapped
def drive(o, my_arg):
print('my_arg', my_arg, 'ret', o.my_method(my_arg=my_arg))
def test():
with patch.object(MyClass, 'my_method', new=func_wrapper(MyClass.my_method)):
o = MyClass()
drive(o, 1)
drive(o, 2)
Run Code Online (Sandbox Code Playgroud)
将输出:
my_arg 1 ret 10000
my_arg 2 ret 0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1209 次 |
| 最近记录: |