【问题标题】:Mock a nested object in Python using Mock()使用 Mock() 在 Python 中模拟嵌套对象
【发布时间】:2019-09-23 23:26:27
【问题描述】:

我有一个父对象,它接收一个连接对象。

我在这个连接对象上运行一个方法来生成一个配置对象。当我嘲笑这个时,我得到的不是Foo

<Mock name='mock().get_properties().property_c' id='1910891784064'>

代码:

# Real

class ClassC:
    property_c = "Foo"

class ClassB:
    def __init__(self):
        pass

    def login(self):
        print("Logged in...")

    def get_properties(self):
        return ClassC()

class ClassA:
    def __init__(self, conn):
        self.conn = conn
        self.conn.login()

a = ClassA(conn=ClassB()) >>> Logged in...
result = a.conn.get_properties()
print(result.property_c) >>> Foo


# Mocked

from unittest.mock import Mock
mock_b = Mock()
mock_c = Mock()
mock_c.property_c.return_value = "Foo_Mock"
mock_b.get_properties.return_value = mock_c

a = ClassA(conn=mock_b())
result = a.conn.get_properties()
print(result.property_c) >>> Output shown above

如何正确地模拟这个?

Edit1 - 建议的重复 S.O 答案仅部分回答了问题。

Edit2 - 我忘了包含模拟登录行为

mock_b.login.return_value = print("Logged in...") awesoon 的回答仍然适用于这个修改:

    mock_b = Mock()
    mock_c = Mock()
    type(mock_c).property_c = PropertyMock(return_value="Foo_Mock")
    mock_b.get_properties.return_value = mock_c
    mock_b.login.return_value = print("Logged in...")

【问题讨论】:

  • 我看到了如何将 PropertyMock 用于 ClassC,但是如何将它注入 ClassB?
  • type(mock_c).property_c = PropertyMock(return_value="Foo_Mock")mock_b.get_properties().property_c 应该可以解决问题。注意我没有打电话给mock_b()
  • 我仍然收到<Mock name='mock().get_properties().property_c' id='1910891784064'>
  • 查看这个:ideone.com/aCy9Ye

标签: python mocking


【解决方案1】:

我认为这行有问题:

a = ClassA(conn=mock_b())

您正在这里创建新的模拟。如果您尝试以下代码:

mock_b = Mock(name='mock_b')
a = ClassA(conn=mock_b())
print(mock_b)
print(a.conn)

您会看到,它们是两个不同的模拟,具有不同的 ID(例如):

<Mock name='mock_b' id='48709360'>
<Mock name='mock_b()' id='48709528'>

最重要的是,您需要将conn=mock_b() 替换为conn=mock_b

如果你解决了这个问题,那么你可以打电话:

print(result.property_c())  # notice extra parathesis.

如果给ClassC加上get_property方法,然后mock方法get_property会更好看。

【讨论】:

  • 我无法按照你的方式构建它。我被api绑定了
  • 好的,所以您可以简单地更改测试中的 2 行:mock_c.property_c.return_value = "Foo_Mock" >> mock_c.property_c = "Foo_Mock" 和:a = ClassA(conn=mock_b()) >> a = ClassA(conn=mock_b)
【解决方案2】:

您的代码中有两个问题:

  1. 在传递给ClassA (a = ClassA(conn=mock_b()) 时不要调用mock_b。调用一个 mock 将创建另一个 mock,它不会包含对 mock_b 所做的更改。

  2. 使用PropertyMock模拟属性:

    type(mock_c).property_c = PropertyMock(return_value="Foo_Mock")
    

    您也可以显式设置属性,但PropertyMock 更灵活。

最终代码为:

from unittest.mock import Mock, PropertyMock
mock_b = Mock()
mock_c = Mock()
type(mock_c).property_c = PropertyMock(return_value="Foo_Mock")
mock_b.get_properties.return_value = mock_c

print(mock_b.get_properties().property_c)

输出:

Foo_Mock

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 2018-11-14
    • 2018-06-01
    相关资源
    最近更新 更多