Skip to content

Argument matching

Creating an expectation with no arguments will by default match all arguments, including no arguments.

flexmock(plane).should_receive("fly").and_return("ok")

Above will be matched by any of the following:

>>> plane.fly()
"ok"
>>> plane.fly("up")
"ok"
>>> plane.fly("up", "down")
"ok"

You can also match exactly no arguments:

flexmock(plane).should_receive("fly").with_args()

Or match any single argument:

flexmock(plane).should_receive("fly").with_args("left")

Matching argument types

In addition to exact values, you can match against the type or class of the argument:

flexmock(plane).should_receive("fly").with_args(object)

Match any single string argument

flexmock(plane).should_receive("fly").with_args(str)

Match the empty string using a compiled regular expression:

regex = re.compile("^(up|down)$")
flexmock(plane).should_receive("fly").with_args(regex)

Match any set of three arguments where the first one is an integer, second one is anything, and third is string 'notes' (matching against user defined classes is also supported in the same fashion):

flexmock(plane).should_receive("repair").with_args(int, object, "notes")

If the default argument matching based on types is not flexible enough, flexmock will respect matcher objects that provide a custom __eq__ method.

For example, when trying to match against contents of numpy arrays, equality is undefined by the library so comparing two of them directly is meaningless unless you use all() or any() on the return value of the comparison.

What you can do in this case is create a custom matcher object and flexmock will use its __eq__ method when comparing the arguments at runtime.

class NumpyArrayMatcher:
    def __init__(self, array):
        self.array = array

    def __eq__(self, other):
        return all(other == self.array)

flexmock(obj).should_receive("function").with_args(NumpyArrayMatcher(array1))

The above approach will work for any objects that choose not to return proper boolean comparison values, or if you simply find the default equality and type-based matching not sufficiently specific.

Multiple argument expectations

It is also possible to create multiple expectations for the same method differentiated by arguments.

flexmock(plane).should_receive("fly").and_return("ok")
flexmock(plane).should_receive("fly").with_args("up").and_return("bad")

Try to execute plane.fly() with any, or no, arguments as defined by the first flexmock call will return the first value.

>>> plane.fly()
"ok"
>>> plane.fly("forward", "down")
"ok"

But! If argument values match the more specific flexmock call the function will return the other return value:

>>> plane.fly("up")
"bad"

The order of the expectations being defined is significant, with later expectations having higher precedence than previous ones. Which means that if you reversed the order of the example expectations above the more specific expectation would never be matched.