我们在python中使用Mock已经有一段时间了。
现在,我们有这样一种情况,我们想模拟一个函数
def foo(self, my_param):
#do something here, assign something to my_result
return my_result
通常,模拟的方法是(假设foo是对象的一部分)
self.foo = MagicMock(return_value="mocked!")
甚至,如果我调用foo()几次,我可以使用
self.foo = MagicMock(side_effect=["mocked once", "mocked twice!"])
现在,我面临这样一种情况:当输入参数具有特定值时,我想返回一个固定值。如果my_param等于something那么我要返回my_cool_mock
这似乎在python的mockito上可用
when(dummy).foo("something").thenReturn("my_cool_mock")
我一直在寻找如何实现同样的Mock没有成功?
什么好主意吗?
你也可以使用@mock.patch.object:
假设my_module.py模块使用pandas从数据库中读取数据,我们想通过模拟pd来测试这个模块。Read_sql_table方法(以table_name作为参数)。
你能做的是(在你的测试中)创建一个db_mock方法,根据提供的参数返回不同的对象:
def db_mock(**kwargs):
if kwargs['table_name'] == 'table_1':
# return some DataFrame
elif kwargs['table_name'] == 'table_2':
# return some other DataFrame
在你的测试函数中,你可以这样做:
import my_module as my_module_imported
@mock.patch.object(my_module_imported.pd, "read_sql_table", new_callable=lambda: db_mock)
def test_my_module(mock_read_sql_table):
# You can now test any methods from `my_module`, e.g. `foo` and any call this
# method does to `read_sql_table` will be mocked by `db_mock`, e.g.
ret = my_module_imported.foo(table_name='table_1')
# `ret` is some DataFrame returned by `db_mock`
虽然side_effect可以实现目标,但是为每个测试用例设置side_effect函数并不方便。
我写了一个轻量级的Mock(称为NextMock)来增强内置Mock来解决这个问题,这里是一个简单的例子:
from nextmock import Mock
m = Mock()
m.with_args(1, 2, 3).returns(123)
assert m(1, 2, 3) == 123
assert m(3, 2, 1) != 123
它还支持参数匹配器:
from nextmock import Arg, Mock
m = Mock()
m.with_args(1, 2, Arg.Any).returns(123)
assert m(1, 2, 1) == 123
assert m(1, 2, "123") == 123
希望这个包能让测试更愉快。请随时提供任何反馈。