模拟被测函数中使用的相同 class 的多个实例

Mocking multiple instances of the same class used in the function-under-test

我有一个使用相同 class 的 2 个实例的函数,我想使用 python 模拟测试该函数。 但我正在打破我的头我怎么能嘲笑这个。 我已经使用我的朋友 Google 和 Whosebug 找到了解决方案,但直到现在还没有找到。

作为简单的模拟示例,展示了我要测试的原理:

class MyClass(object): # this class is inside a module I'm not allowed to change.
    def __init__(self, name, value):
        self._name  = name
        self._value = value

    def get_value(self):
        return self._value

然后是被测模块(又是一个模拟实现来展示这个想法):

import my_class_module

def my_function():
    a = my_class_module.MyClass('a', 3)
    b = my_class_module.MyClass('b', 4)

    return a.get_value() + b.get_value()

我想到的 my_function 单元测试的全局想法如下(当然这个想法目前还行不通):

mock.patch('module.my_class_module.MyClass')
def test_my_function(self, mock_my_class):
    def _my_get_value(self): # ideally I would like to use get_value.return_value per instance, but I don't know how.
        if self._name == 'a':
            return 4 # Different values to make sure that we can verify that the mock is called
        else:
            return 5

    # Next line is the one I'm wondering about since mock_myh_class.return_value should differ for each instance.
    # But again this next line is already a work-around idea, since I don't know how to set the return-value of get_value for each instance.
    mock_my_class.return_value.get_value.side_effect = my_get_value 

    exp_result = 9

    result = module.my_function()

    self.assertEqual(result, exp_result)

我缺少什么来完成这项工作?又名:我如何模拟相同 class 的 2 个实例?

您可以使用 mock.side_effect 创建 MyClass 的不同模拟实例。

例如

myclass.py:

class MyClass(object):
    def __init__(self, name, value):
        self._name = name
        self._value = value

    def get_value(self):
        return self._value

myfunction.py:

import myclass


def my_function():
    a = myclass.MyClass('a', 3)
    b = myclass.MyClass('b', 4)
    print('a:\n', a)
    print('b:\n', b)
    print('a and b are different instances of MyClass:', a != b)
    return a.get_value() + b.get_value()

test_myfunction.py:

import unittest
from unittest import mock
import myfunction


class TestMyFunctionModule(unittest.TestCase):
    @mock.patch('myclass.MyClass')
    def test_my_function(self, mock_my_class):
        myclassInstanceMocks = [mock.Mock(name='a'), mock.Mock(name='b')]
        myclassInstanceMocks[0].get_value.return_value = 4
        myclassInstanceMocks[1].get_value.return_value = 5
        mock_my_class.side_effect = myclassInstanceMocks
        exp_result = 9
        result = myfunction.my_function()
        self.assertEqual(result, exp_result)


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

带有覆盖率报告的单元测试结果:

a:
 <Mock name='a' id='4572131536'>
b:
 <Mock name='b' id='4572149072'>
a and b are different instances of MyClass: True
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Name                                            Stmts   Miss  Cover   Missing
-----------------------------------------------------------------------------
src/Whosebug/64170793/myclass.py               6      3    50%   3-4, 7
src/Whosebug/64170793/myfunction.py            8      0   100%
src/Whosebug/64170793/test_myfunction.py      14      0   100%
-----------------------------------------------------------------------------
TOTAL                                              28      3    89%