【问题标题】:With unittest.mock, How to mock a class property with return_value depending on instance attribute?使用 unittest.mock,如何根据实例属性模拟具有 return_value 的类属性?
【发布时间】:2021-08-21 18:12:37
【问题描述】:

我有两个课程AB。我想测试A 的函数foo_a。使用一些业务逻辑,foo_a 创建两个可能的 B 实例(具有不同的参数)并调用函数 foo_bB

class A:
  def foo_a(self, *args, **kwargs):
    # some code above
    if condition_1:
      foo_b_result = B(**arguments_1).foo_b()
    else:
      foo_b_result = B(**arguments_2).foo_b()
    # some code below that returns foo_b_result + other objects independent of foo_b_result

问题在于foo_b 是一个调用API 和其他东西的复杂函数。我不想在这个单元测试中模拟 API,以便foo_b 返回适当的输出,事实上,foo_b 已经在我的类B 的单元测试集中的其他地方进行了测试。因此,在这种情况下,我更关心arguments_1arguments_2 的正确性,而不是foo_b_result 的正确性。因此,如果我可以模拟foo_b 会很好,这样它返回的输出可以很容易地显示foo_b 是否已被B 的正确实例调用。例如,foo_b 可以返回 arguments_1arguments_2

在这种情况下,也许还有另一种更好的单元测试方法foo_a,欢迎提出任何想法。

更新:另一种方法是创建一个以condition_1 为输入并返回arguments_1arguments_2 的新函数(此函数可以轻松测试)。然后我会模拟 foo_b 以便它总是返回相同的值(例如 0)。但是,知道是否可以模拟 foo_b 以便它根据 arguments_1arguments_2 返回值会很有趣。

【问题讨论】:

  • 你想模拟foo,具体是什么意思?你的意思是你想用测试替身替换MyClass 实例?
  • 刚刚编辑了问题。更清晰?
  • 并非如此。如果你正在测试MyClass,你不应该嘲笑它的任何部分。如果您正在测试 使用 MyClass 的东西,为什么不通过它,例如MyClass(a=0),其foo 方法会根据需要返回0
  • "显示 foo_b 是否已被 B 的正确实例调用" - 不,您需要显示它是否已被调用 on i> B 的正确实例,这实际上只是意味着 B 的调用方式。您可以在例如查看如何模拟课程。 stackoverflow.com/a/38199345/3001761,然后您可以断言 B 的模拟是用什么调用的。对于这种情况,您不需要将真实行为(“它根据arguments_1arguments_2 返回值”)放入测试替身中。
  • Mocks 有很多方法来断言交互:docs.python.org/3/library/…

标签: python-3.x mocking


【解决方案1】:

感谢@jonrsharpe,我最终得到了以下解决方案:

from unittest import mock
from unittest.mock import MagicMock

@mock.patch('a.B')  # a.py contains class A with an import of class B
def test_foo_a(mock_b):  # mock_b mocks class B
  return_value_foo_b = "whatever"
  mock_b().foo_b = MagicMock(return_value=return_value_foo_b)
  # instantiate A in a variable called a, then:
  expected_foo_a = (return_value_foo_b,) # + other objects independent of foo_b_result
  assert a.foo_a() == expected_foo_a
  mock_b.assert_called_with(arguments_1)  # condition_1 is met.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 2016-04-27
    • 2021-11-16
    • 2020-06-19
    • 1970-01-01
    相关资源
    最近更新 更多