Search code examples
pythonunit-testingmockingpython-mock

Patching one occurrence on the function call in Python's Mock


Suppose I patch and mock certain function foo() which implements reading multiple files. So we have multiple open() calls:

def foo():
    a=open("stuff.txt")
    b=open("another_thing.txt")
    c=open("last_one.txt")

If I do mock.patch("__builtin__.open", return_value='kaboom'), the first occurrence of open() will be patched, the one reading file named "stuff.txt".

What if I need to patch second(any other) open() calls in foo() to mock return_value from reading, say another_thing.txt?


Solution

  • Because you don't like the best answer (the Daniel's one) I can tell how you can do it by side_effect:

    >>> import mock
    >>> with mock.patch("__builtin__.open", side_effect = ["kaboom", "more","moremore"]):
    ...     assert "kaboom" == open("stuff.txt")
    ...     assert "more" == open("another_thing.txt")
    ...     assert "moremore" == open("last_one.txt")
    

    Or better

    >>> with mock.patch("__builtin__.open", side_effect = lambda name, *args: name):
    ...     assert "stuff.txt" == open("stuff.txt")
    ...     assert "another_thing.txt" == open("another_thing.txt")
    ...     assert "last_one.txt" == open("last_one.txt")
    

    I wrote a comment that I think is important in this answer context: this is a wrong way to do these kind of tests. In this test you are writing wires that tangle tests and production code.

    If you cannot refactor your code to write it in a more modular and testable way you should use this test to check the behavior and immediately after use it to refactor your code without change the behavior. Last step will be rewrite your test by use refactored code and then remove old test.