如何从导入的模块中正确模拟类和方法

时间:2019-06-03 16:43:59

标签: python python-unittest

我正在尝试为一种方法创建一些单一测试,该方法需要使用我不想使用的外部模块中的类来实例化某些对象,因为它们需要在对象初始化时无法传递的参数。 / p>

例如,假设我要测试的代码具有以下结构:

from module_one import Class_1
from module_two import Class_2

class MyMainClass()
    def method_to_be_tested(self, stuff):
        var_one = Class_1(stuff.data)
        self.var_two = Class_2(var_one.data)
        print("The var is %s" % self.var_two.attribute)

stuff是一个复杂的参数,具有几个我无法嘲笑的属性。

这是我使用patch中的unittest.mock在测试方法中尝试过的方法(但没有用):

@patch('module_two.Class_2')
@patch('module_one.Class_1')
def test_method(self, mocked_class1, mocked_class2):
    stuff = mock()
    mocked_class1.return_value = 'some_stuff_that_i_dont_want'
    mock_class2 = mock()
    mock_class2.attribute = 'what_i_want_to_get'
    mocked_class2 = mock_class2
    mymainclass.method_to_be_tested(stuff)
    assertEqual('what_i_want_to_get', mymainclass.var_two.attribute)

似乎补丁或某些东西不起作用,因为它引发了一个错误,告诉我 str对象没有属性数据,当var_one时指的是var_one.data用作Class2的参数。

我想要的是将任何参数传递给Class2,并始终获得我在mock_class2中定义的内容。

编辑:mock()是从mockito模块导入的,但是也许我不需要它来实现所需的功能。

1 个答案:

答案 0 :(得分:0)

您当然可以在没有模拟的情况下做到这一点。假设在模块MyMainClass中定义了mainmodule

import unittest.mock as mock


class TestMyMainClass(unittest.TestCase):
    @mock.patch('mainmodule.Class_2')
    @mock.patch('mainmodule.Class_1')
    def test_method(self, mocked_class1, mocked_class2):
        stuff = mock.Mock()
        mocked_class2_instance = mock.Mock()
        mocked_class2_instance.attribute = 'what_i_want_to_get'
        mocked_class2.return_value = mocked_class2_instance
        mymainclass = MyMainClass()
        mymainclass.method_to_be_tested(stuff)
        self.assertEqual('what_i_want_to_get', mymainclass.var_two.attribute)


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

现在,如果您认为此测试很糟糕,我必须同意。

  • 您必须修补Class_1,但它甚至没有出现在测试中。
  • 除非您熟悉被测方法的内部实现细节,否则为什么Class_2根本没有意义是不明显的。实际上,您是在测试实现细节,而不是(或除了)可观察到的行为(通常是不好的)。
  • 该方法的行为(希望)取决于stuff.data,但是测试将忽略该问题,并将愉快地通过任何检查。还需要一个stuff属性的data对象,即使您不在乎它是什么。

这里的主要问题是,通过在方法内部实例化Class_1Class_2可以紧密地耦合这三段代码,但是现在您想单独测试它们。这将很困难,并且可能会导致脆弱和难以阅读的测试。

如果您真的希望代码像这样,我建议您在不模拟Class_1Class_2的情况下测试该方法。现在,如果您说您不想这样做,是因为stuff(或者更好的是stuff.data;为什么只需要数据时就将整个想法传递给他人?)很难模拟或实例化,我想您的设计有问题,但是据我从您的人为示例中可以得出的结论。