Python unittest的设置函数不使用在类上声明的模拟

问题描述

所以我在编写单元测试时遇到了设置函数方面的问题。在我看来,它应该只是在你的函数之前执行代码,所以我可以把任何重复的东西放在里面。然而,这个函数似乎并没有将我作为补丁修饰器创建的模拟应用到整个类上。这是我希望它看起来是什么样子的一小部分:

@patch('geomet_data_registry.layer.base.get_today_and_now', new=mocked_get_date)  # noqa
@patch('geomet_data_registry.layer.base.load_plugin', new=mocked_load_plugin)
@patch('geomet_data_registry.layer.base.TILEINDEX_PROVIDER_DEF', new=mocked_tileindex)  # noqa
@patch('geomet_data_registry.layer.base.STORE_PROVIDER_DEF', new=mocked_store)
class TestInitBase(unittest.TestCase):

    def setUp(self):
        """ Code that executes before every function. """

        self.maxDiff = None
        self.today_date = 
            datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
        mocked_get_date.return_value = self.today_date
        self.base_layer = BaseLayer({'name': 'model_gem_global'})

    def test_Init(self):
        
        expected_values = {'items': [],...

        base_layer_attr = self.base_layer.__dict__

        self.assertDictEqual(expected_values, base_layer_attr, msg=None)
在这里,我模拟收到的日期,这样它就不会扰乱我的测试,我模拟Load_plugin,当使用它时,它返回某个插件的类实例,我模拟TileIndex,它是ES TileIndex,我模拟商店,这是一个redis商店。如果我使用上面显示的代码,它不能工作。当我在setUp中实例化类BaseLayer时,没有使用我的模拟,我得到:

-  'receive_datetime': '2021-11-10T12:56:07.371067Z',
?                                              ^^^
+  'receive_datetime': '2021-11-10T12:56:07.371131Z',
?                                              ^^^
-  'store': <MagicMock name='mock()' id='140158154534472'>,
-  'tileindex': <MagicMock name='mock()' id='140158154534472'>,
+  'store': <BaseStore> Redis,
+  'tileindex': <ElasticsearchTileIndex> http://localhost:9200,
但是,在您告诉我我的路径对于模拟之类的东西可能是错误的之前,我可以向您保证,一切都运行得很好,因为如果我保持所有内容不变,代码就会运行,只是我在每个测试函数中重复了类实例化。此外,如果我将其保持不变,它将起作用,但我将setUp命名为mySetUp,并在函数开始时调用它。

一切都是这样工作的,我已经进行了所有的测试,而根本没有使用setUp,因为我记得我对自己说,这个东西坏了,我不会冒险在我的测试中使用这个函数。

谢谢!


解决方案

问题是mock.patch修饰符应用于每个测试函数,而在setUp期间尚未完成修补。 要对所有测试使用相同的模拟,您必须在setUp/tearDown中开始/停止模拟。这可能类似于:

class TestInitBase(unittest.TestCase):

    def setUp(self):
        self.data_patcher = patch('geomet_data_registry.layer.base.get_today_and_now',
            new=mocked_get_date)
        self.data_patcher.start()
        self.plugin_patcher = patch('geomet_data_registry.layer.base.load_plugin',
            new=mocked_load_plugin)
        self.plugin_patcher.start()
        ...

        self.today_date = 
            datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
        mocked_get_date.return_value = self.today_date
        self.base_layer = BaseLayer({'name': 'model_gem_global'})

    def tearDown(self):
        self.data_patcher.stop()
        self.plugin_patcher.stop()
        ...

诚然,这不如使用装饰符。您仍然可以将修饰符用于不需要在setUp中打补丁的函数(如果有)。

附注:有了pytest,这就不那么麻烦了,因为您可以将安装和拆卸部分放在同一个夹具中。

相关文章