【问题标题】:Patching one occurrence on the function call in Python's Mock在 Python 的 Mock 中修补函数调用的一次事件
【发布时间】:2016-01-19 11:54:24
【问题描述】:

假设我修补并模拟了某些实现读取多个文件的函数 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

【问题讨论】:

    标签: python unit-testing mocking python-mock


    【解决方案1】:

    因为你不喜欢最好的答案(丹尼尔的那个)我可以通过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")
    

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

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

    【讨论】:

    • 这是我问题的最佳答案。丹尼尔的很好,但在我的情况下完全没用。我根本无法更改需要测试的代码。
    • 所以,编写您的测试,然后更改代码,最后更改您的测试。该测试将在这里检查您的行为,但这是错误的方法,因为它会将您的生产代码与您的测试纠缠在一起:因此您应该尽快将其删除。
    • 除了我编写测试来修复代码这一事实之外,使用 side_effects 有什么不好的,反之亦然?
    • side_effect 本身并没有错,错误的是编写测试引入了一个并不真正重要的协议。在side_effect 的第一个版本中,您应该注意打开文件的顺序。如果这个顺序不重要,那么您将引入一些会使您的测试不太灵活的东西。
    【解决方案2】:

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

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

    【讨论】:

    • 我会抓住副作用的机会。如何使用它来分配返回值?
    猜你喜欢
    • 2012-05-03
    • 2012-04-24
    • 1970-01-01
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2014-09-02
    相关资源
    最近更新 更多