简体   繁体   English

未直接调用的 Python mocking function

[英]Python mocking function that isn't called directly

In my object, I have several "Loader" functions for different types of data that might require loading.在我的 object 中,我有几个“加载器”函数,用于可能需要加载的不同类型的数据。 They're stored as:它们存储为:

import foo
import bar

class MyClass
    LOADERS = {
        'foo': {
            'context_manager': False,
            'func': foo.data.loader,
            'kwargs': {'data_orientation': 'columns'}
            },
        'bar': {
            'context_manager': True,
            'func': bar.load_data
            'kwargs': {}
            }
        }

    def load_data(self, load_type, path):
        func = self.LOADERS[load_type]['func']
        kwargs = self.LOADERS[load_type]['kwargs']
        if self.LOADERS[load_type]['context_manager']:
            with open(path, 'rb') as f:
                self.data=func(f, **kwargs)
        else:
            self.data = func(path, **kwargs)

This is working very well in practice, but I'm finding it's murder to test .这在实践中效果很好,但我发现测试是谋杀。

When I write my test:当我写我的测试时:

from mock import MagicMock, patch
import sys

sys.modules['foo'] = MagicMock()
sys.modules['bar'] = MagicMock()

from mypackage import MyClass

@patch('foo.data.loader')
def test_load_foo(mock_loader):
    my_obj = MyClass()
    my_obj.load_data('foo', 'path/to/data')
    mock_loader.assert_called_once()

it fails.它失败。 Called 0 times.调用 0 次。

I halfway suspect that it's because it's not being called directly.我有一半怀疑这是因为它没有被直接调用。 But that shouldn't really matter.但这应该不重要。

Can anyone offer any suggestions?任何人都可以提供任何建议吗? I'm using pytest as my testing engine, but I've found it plays nicely with mock in the past.我使用 pytest 作为我的测试引擎,但我发现它在过去与 mock 配合得很好。

Thanks!谢谢!

The issue arises because you are trying to patch a function within a class attribute as opposed to an instance attribute.出现此问题是因为您尝试在class属性而不是实例属性中修补 function。 The behavior is not the same.行为不一样。 This does however offer us some flexibility as it is a class attribute, thus we can modify the object directly on the class we instantiate in our test.然而,这确实为我们提供了一些灵活性,因为它是一个class属性,因此我们可以直接在我们在测试中实例化的 class 上修改 object。

from unittest.mock import MagicMock

from mypackage import MyClass


def test_load_foo():
    key_to_test = "foo"
    mock_loader = MagicMock()
    
    my_obj = MyClass()
    my_obj.LOADERS[key_to_test]["func"] = mock_loader
    my_obj.load_data(key_to_test, 'path/to/data')
    mock_loader.assert_called_once()

Instead of trying to patch the function, we modify our objects instance to use the MagicMock .我们没有尝试修补 function,而是修改我们的对象实例以使用MagicMock

Using this approach I receive the following message:使用这种方法,我收到以下消息:

collected 1 item                                                                                                                                                

tests/test_mypackage.py .                                                                                                                                 [100%]

======================================================================= 1 passed in 0.01s =======================================================================

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM