测试实例中的方法是否已在mock中调用

问题描述 投票:4回答:2

我有这种设置,我正在测试一个使用另一个类的类,我想模仿后者,所以我只测试第一个类本身。

nuclear_reactor.py

class NuclearReactor():
    def __init__(self):
        print "initializing the nuclear reactor"

    def start(self):
        print "starting the nuclear reactor"

nuclear_manager.py

from nuclear_reactor import NuclearReactor

class NuclearManager():
    def __init__(self):
        print "manager creating the nuclear reactor"
        self.reactor = NuclearReactor()

    def start(self):
        print "manager starting the nuclear reactor"
        self.reactor.start()

test_nuclear_manager.py

from mock import Mock
import nuclear_manager
from nuclear_manager import NuclearManager

def test():
    mock_reactor = nuclear_manager.NuclearReactor = Mock()
    nuke = NuclearManager()
    nuke.start()
    nuke.start()
    print mock_reactor.mock_calls
    print mock_reactor.start.call_count

test()

我想测试的是调用NuclearReactor.start,但是当我运行它时,我得到:

manager creating the nuclear reactor
manager starting the nuclear reactor
manager starting the nuclear reactor
[call(), call().start(), call().start()]
0

我完全理解,因为start是实例的属性而不是类的属性,我可以解析mock_calls,但是有没有更好的方法来检查实例化的模拟类的调用是什么?

我可以在NuclearManager中使用依赖注入来传递一个模拟NuclearReactor,但我想有一种替代方法只使用mock。

python python-2.7 unit-testing mocking
2个回答
5
投票

您确实在测试是否已在类上直接调用start,而您的代码却没有。您可以直接在实例上测试该方法;记住通过调用类生成实例:

print mock_reactor.return_value.calls
print mock_reactor.return_value.start.call_count

Mock.return_value attribute是对模拟类的调用的结果,所以实例。

你也可以调用mock。默认情况下,Mocks在调用时总是返回完全相同的对象,一个表示该返回值的新模拟:

print mock_reactor().calls
print mock_reactor().start.call_count

调用mock实例和mock实例return_value属性的结果是同一个。

通过打印出对NuclearReactor模拟的调用你已经走在了正确的道路上,你只是错过了在被调用的模拟器上调用start()的细节,所以记录了call().start(),而不是start()

您可能希望使用mock.patch()来处理修补,而不是直接分配;这可以确保再次删除补丁,以便其他测试可以自行决定模拟的内容:

import mock
from nuclear_manager import NuclearManager

@mock.patch('nuclear_manager.NuclearReactor')
def test(mock_reactor):
    nuke = NuclearManager()
    nuke.start()
    nuke.start()

    instance = mock_reactor.return_value
    assert instance.start.call_count == 2
    instance.assert_called()

我在这里用它作为装饰者;当调用test()函数时,mock被放置到位,当函数退出时,它会被再次删除。您还可以使用patch()作为上下文管理器来更精细地限制补丁的范围。

此外,对于像这样的单元测试,请使用unittest library

import mock
import unittest
import nuclear_manager

class NuclearManagerTests(unittest.TestCase):
    @mock.patch('nuclear_manager.NuclearReactor')
    def test_start(self, mock_reactor):
        nuke = NuclearManager()
        nuke.start()
        nuke.start()

        instance = mock_reactor.return_value
        self.assertEqual(instance.start.call_count, 2)
        instance.assert_called()

if __name__ == '__main__':
    unittest.main()

这使您可以将测试适合更大的测试套件,启用和禁用测试,以及与其他测试工具集成。


-2
投票

我使用模拟的方式是这样的:(代码是Python 3)

from unittest.mock import MagicMock

class NuclearManager():
    def __init__(self, reactor):
        print("manager creating the nuclear reactor")
        self.reactor = reactor

    def start(self):
        print("manager starting the nuclear reactor")
        self.reactor.start()


def test():
    mock_reactor = MagicMock()
    nuke = NuclearManager(mock_reactor)
    nuke.start()
    nuke.start()

    # These two prints would actually be asserts of some sort
    print(mock_reactor.mock_calls)
    print(mock_reactor.start.call_count)

test()

输出:

manager creating the nuclear reactor
manager starting the nuclear reactor
manager starting the nuclear reactor
[call.start(), call.start()]
2
© www.soinside.com 2019 - 2024. All rights reserved.