使用Mock()在Python中模拟嵌套对象

时间:2019-05-06 10:26:03

标签: python mocking

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

我在此连接对象上运行方法以生成配置对象。当我嘲笑它时,我得到的不是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...")

2 个答案:

答案 0 :(得分:1)

您的代码中有两个问题:

  1. 在传递给mock_bClassA)时不要呼叫a = ClassA(conn=mock_b()。调用模拟将创建另一个模拟,并且将不包含对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

答案 1 :(得分:0)

我认为这行有问题:

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.

如果将get_property方法添加到ClassC,然后模拟方法get_property,看起来会更好。