多次调用方法的 Python Mock 对象
我正在测试一个类,它具有另一个类的依赖项(该类的实例被传递给 CUT 的 init 方法)。我想使用 Python Mock 库来模拟这个类。
我所拥有的是这样的:
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.return_value = "the value I want the mock to return"
assertTrue(mockobj.methodfromdepclass(42), "the value I want the mock to return")
cutobj = ClassUnderTest(mockobj)
这很好,但是“methodfromdepclass”是一个参数化方法,因此我想创建一个模拟对象,其中根据传递给 methodfromdepclass 的参数,它返回不同的值。
我想要这种参数化行为的原因是我想创建包含不同值的 ClassUnderTest 的多个实例(这些值是由从模拟对象返回的值生成的)。
有点像我在想的(这当然行不通):
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.ifcalledwith(42).return_value = "you called me with arg 42"
mockobj.methodfromdepclass.ifcalledwith(99).return_value = "you called me with arg 99"
assertTrue(mockobj.methodfromdepclass(42), "you called me with arg 42")
assertTrue(mockobj.methodfromdepclass(99), "you called me with arg 99")
cutinst1 = ClassUnderTest(mockobj, 42)
cutinst2 = ClassUnderTest(mockobj, 99)
# now cutinst1 & cutinst2 contain different values
我如何实现这种“ifcalledwith”类型的语义?
I have a class that I'm testing which has as a dependency another class (an instance of which gets passed to the CUT's init method). I want to mock out this class using the Python Mock library.
What I have is something like:
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.return_value = "the value I want the mock to return"
assertTrue(mockobj.methodfromdepclass(42), "the value I want the mock to return")
cutobj = ClassUnderTest(mockobj)
Which is fine, but "methodfromdepclass" is a parameterized method, and as such I want to create a single mock object where depending on what arguments are passed to methodfromdepclass it returns different values.
The reason I want this parameterized behaviour is I want to create multiple instances of ClassUnderTest that contain different values (the values of which are produced by what gets returned from the mockobj).
Kinda what I'm thinking (this of course does not work):
mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.ifcalledwith(42).return_value = "you called me with arg 42"
mockobj.methodfromdepclass.ifcalledwith(99).return_value = "you called me with arg 99"
assertTrue(mockobj.methodfromdepclass(42), "you called me with arg 42")
assertTrue(mockobj.methodfromdepclass(99), "you called me with arg 99")
cutinst1 = ClassUnderTest(mockobj, 42)
cutinst2 = ClassUnderTest(mockobj, 99)
# now cutinst1 & cutinst2 contain different values
How do I achieve this "ifcalledwith" kind of semantics?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
尝试
副作用
Try
side_effect
更甜蜜一点:
或对于多个参数:
或使用默认值:
或两者的组合:
我们愉快地前进。
A little sweeter:
or for multiple arguments:
or with a default value:
or a combination of both:
and merrily on high we go.
我在进行自己的测试时遇到了这个问题。如果您不关心捕获对 methodfromdepclass() 的调用,而只是需要它返回某些内容,那么以下内容可能就足够了:
这是一个参数化版本:
I've ran into this when I was doing my own testing. If you don't care about capturing calls to your methodfromdepclass() but just need it to return something, then the following may suffice:
Here's a parameterized version:
如此处所示,除了在 unittest.mock.Mock 你也可以使用
@mock.patch.object
和new_callable
,它允许您使用模拟对象修补对象的属性。假设一个模块
my_module.py
使用pandas
从数据库中读取数据,我们想通过模拟pd.read_sql_table
方法来测试这个模块(它以table_name
作为参数)。您可以做的是(在您的测试中)创建一个 db_mock 方法,该方法根据提供的参数返回不同的对象:
然后在您的测试函数中执行以下操作:
As in here, apart from using
side_effect
in unittest.mock.Mock you can also use@mock.patch.object
withnew_callable
, which allows you to patch an attribute of an object with a mock object.Let's say a module
my_module.py
usespandas
to read from a database and we would like to test this module by mockingpd.read_sql_table
method (which takestable_name
as argument).What you can do is to create (inside your test) a
db_mock
method that returns different objects depending on the argument provided:In your test function you then do:
您可以使用 Side Effect + Dict Dispatch Pattern 来获得更干净的代码:
例如(使用异步,忽略非异步情况下的未来对象)
You can use Side Effect + Dict Dispatch Pattern for a more clean code:
For example (using async, ignore future objects for non async cases)