Python模拟对象,其方法被多次调用

2024-06-03 01:16:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个正在测试的类,它作为依赖关系有另一个类(它的一个实例被传递给CUT的init方法)。我想使用Python模拟库模拟这个类。

我有的是:

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返回的内容生成)。

有点像我想的(这当然不行):

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”语义?


Tags: the实例you参数returnvaluewitharg
3条回答

稍微甜一点:

mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}[x]

或者对于多个参数:

mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}[x]

或使用默认值:

mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}.get(x, 20000)

或两者结合:

mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}.get(x, 20000)

我们高高兴兴地走。

我自己做测试的时候碰到过这个问题。如果您不关心捕获对methodfromdepclass()的调用,而只是需要它返回一些内容,那么以下内容就足够了:

def makeFakeMethod(mapping={}):
    def fakeMethod(inputParam):
        return mapping[inputParam] if inputParam in mapping else MagicMock()
    return fakeMethod

mapping = {42:"Called with 42", 59:"Called with 59"}
mockobj.methodfromdepclass = makeFakeMethod(mapping)

以下是参数化版本:

def makeFakeMethod():
    def fakeMethod(param):
        return "Called with " + str(param)
    return fakeMethod

尝试side_effect

def my_side_effect(*args, **kwargs):
    if args[0] == 42:
        return "Called with 42"
    elif args[0] == 43:
        return "Called with 43"
    elif kwargs['foo'] == 7:
        return "Foo is seven"

mockobj.mockmethod.side_effect = my_side_effect

相关问题 更多 >