【问题标题】:Override 'is' operator for mocked object覆盖模拟对象的“is”运算符
【发布时间】:2021-01-27 15:13:59
【问题描述】:

简化代码:我有一个函数,它需要一个数字或 None,如果是 None,则返回 True,如果是数字,则返回 False,例如:

def function(var):
    return var is None

我想传递一个模拟对象并使用is 运算符对其进行测试,如下所示:

from unittest.mock import Mock

mock = Mock(return_value=None)
assert function()

尽管我将值嘲笑为None,但这将失败。根据documentation,支持的魔术方法有很多,但没有一个让我实现这种情况下的行为。

更改为assert mock == None 可以让我使用__eq__ 运算符,但我不想接触代码(根据this answer,显然使用is== 快)

【问题讨论】:

  • 您无法更改is
  • 你怎么能说is 如果你想同时实现两者会更快?
  • "更改为 assert mock == None 会让我使用 eq 运算符,但我想避免它,因为显然使用 is 比 == 根据 this回答。”这不会是一个重大的性能问题
  • @juanpa.arrivillaga: 可能不是性能问题,但性能有差异 >>> timeit.Timer("None == None").timeit() 0.026401887999782048 >>> timeit.Timer ("None is None").timeit() 0.02391680099935911 顺便说一句,这些是平均值
  • @ezib 因为该语言没有为is 提供钩子,这总是意味着身份。

标签: python mocking overriding python-unittest python-unittest.mock


【解决方案1】:

也许使用isinstance() 而不是is 对你有用。将模拟对象类声明为 class MockInt(int): 将使 isinstance() 将变量识别为 int:

class MockInt(int):
      def __init__(self,value): self.value = value

i = MockInt(23)

print( isinstance(i,int) ) # True 

【讨论】:

    【解决方案2】:

    正如许多人所指出的,is 是“不可覆盖的”,因为它是对 id 的快速相等检查。这就是与 __eq__ 相比存在性能差异的原因。

    the docsthis answer 的 cmets 中了解更多信息。

    【讨论】:

      【解决方案3】:

      TL;DR

      当有return_value时不要忘记括号

      from unittest.mock import Mock
      
      mock = Mock(return_value=None)
      assert function(mock())
      

      更多信息

      如果您想传递一个包含None 的变量来测试function,则无需使用Mock。您可以编写以下代码:

      mock = None
      assert function(mock)
      

      Mock 的最佳用法是当您想要模拟具有更复杂结构的方法或对象时。因此,当您编写 mock = Mock(return_value=None) 时,您必须调用 mock 以返回 return_value

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-02
        • 2015-04-09
        • 1970-01-01
        • 2016-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多