【发布时间】:2018-10-21 23:18:40
【问题描述】:
我的测试代码是这样的:
def to_be_tested(x):
return round((x.a + x.b).c())
我想通过将 Mock 对象作为 x 传递来测试它。我试着这样做:
import unittest
import unittest.mock
class Test_X(unittest.TestCase):
def test_x(self):
m = unittest.mock.Mock()
to_be_tested(m)
# now check if the proper call has taken place on m
对x.a 的调用和对x.b 的调用按预期工作。他们提供了新的模拟对象,可以询问它们是如何创建的(例如通过q._mock_parent 和q._mock_new_name),所以这一步工作得很好。
但随后应该进行添加,这只会引发错误 (TypeError: unsupported operand type(s) for +: 'Mock' and 'Mock')。我希望这也能返回一个模拟对象,以便可以调用 .c() 并(再次)返回一个模拟对象。
在调用被测代码之前,我也考虑过m.__add__ = lambda a, b: unittest.mock.Mock(a, b),但这无济于事,因为要添加的不是我原来的 Mock,而是一个新创建的。
我还尝试了(已经很麻烦的)m.a.__add__ = lambda a, b: unittest.mock.Mock(a, b)。但这(令我惊讶)导致在调用被测代码时引发AttributeError: Mock object has no attribute 'c'。我不明白,因为我在那里创建的 Mock 应该接受我在其中调用 c(),对吗?
有什么方法可以实现我想要的吗?如何创建能够添加到另一个 Mock 的 Mock?
或者有像我这样的单元测试代码的另一种标准方法吗?
编辑:我对提供专门的代码准备为预期调用传递的模拟不感兴趣。我只想在调用后通过检查传递和返回的模拟对象来检查一切是否按预期进行。我认为这种方式应该是可能的,并且在这种情况下(以及其他类似的复杂情况)我可以使用它。
【问题讨论】:
-
投反对票的人:请说明您对我的问题不满意的地方。
-
简单的没有足够的信息可用。没有关于
class X的信息,2 个datetime.datetime对象自然不能加在一起。如果您只在评论中添加它们,我认为我现在无法投票,我认为您必须更新原始帖子 -
@Gang 原来使用了两个
datetime对象的差异,这是可能的,应该返回一个datetime.timedelta()。我只是想提供一个minimal reproducible example 而不提供详细信息。我知道,考虑到所有细节,您可能已经能够提出一个专门的版本,但是使用我想要理解和使用的机制(传递 Mock 对象并在之后签入),这将不是一个合适的解决方案)。我在我的 Q 中添加了一个 EDIT 部分,以使任何反对者能够撤销他们的决定(以防万一)。 -
请注意,
unittest.mock不提供__round__模拟实现可能是有充分理由的:文档明确指出,此类方法应返回 Integral(整数)类型,模拟对象不是。因此,您通常需要提供自己的__round__实现。 -
也就是说,由于所有其他数字舍入方法都存在(trunc、ceil 和 floor),我已提交 bugs.python.org/issue33516 以在核心库中解决此问题。
标签: python-3.x unit-testing mocking