Take the 2-minute tour ×

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?

share|improve this question
add comment

3 Answers

up vote 22 down vote accepted

Try 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 kwarg['foo'] == 7:
        return "Foo is seven"

mockobj.mockmethod.side_effect = my_side_effect
share|improve this answer
Awesome, exactly what I needed. Not a fan of the syntax, but works awesome. Thanks! –  Adam Parkin Oct 5 '11 at 18:19
add comment

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:

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

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

Here's a parameterized version:

def makeFakeMethod():
    def fakeMethod(param):
        return "Called with " + str(param)
    return fakeMethod
share|improve this answer
+1: tighter syntax than the if-block pattern with side_effect, maybe return Mock() instead of none so that default behavior is maintained? –  Conrad.Dean Jul 16 '13 at 14:42
add comment

A little sweeter:

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

or for multiple arguments:

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

or with a default value:

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

or a combination of both:

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

and merrily on high we go.

share|improve this answer
Little terse, but I like it. What if the lambda returned a Mock instance so that the unaccounted behaviors revert back to the regular behavior of the mock library? –  Conrad.Dean Jul 16 '13 at 14:45
add comment

Your Answer


