在 Python 的 Mock 中修补一次函数调用

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

假设我修补并模拟了某个实现读取多个文件的函数 foo()。所以我们有多个 open() 调用:

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

如果我这样做 mock.patch("__builtin__.open", return_value='kaboom'),第一次出现的 open() 将被修补,读取名为 "stuff.txt".

的文件

如果我需要修补 foo() 中的第二个(任何其他)open() 调用以模拟 return_value 阅读,比如 another_thing.txt

可以通过 Mock 的 side_effect 参数来做到这一点,但我不建议这样做。相反,重构您的代码,以便每个打开的调用都发生在一个单独的函数中,您可以单独修补它。

a = open_stuff()
b = open_another_thing()
c = open_last_one()

因为你不喜欢最佳答案(大牛的那个)我可以告诉你怎么做 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")

或更好

>>> 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")

我写了一条我认为在这个答案上下文中很重要的评论:这是进行此类测试的错误方法。在此测试中,您正在编写将测试和生产代码纠缠在一起的连线。

如果您无法重构您的代码以以更模块化和可测试的方式编写它,您应该使用此测试来检查行为,并在使用它之后立即重构您的代码而不改变行为。最后一步是使用重构代码重写测试,然后删除旧测试。