简要总结

MyClass.my_method调用了instance = SomeLibrary()我想创建一个模拟,因此instance是我可以控制的模拟对象。本着隔离测试的精神,我实际上不想调用SomeLibrary

传递给@mock.patch()的参数

我正在尝试模拟类构造函数,但是我还没有弄清楚要传递给@ mock.patch()装饰器的内容。文档说该参数必须完全加点(pyftdi.ftdi.Ftdi),但是where to patch文档说该参数必须与被测试的代码知道它的名称(Ftdi)相匹配。我看不出如何同时满足这两个条件。

具体来说,这是要测试的文件:

from pyftdi.ftdi import Ftdi

class FtdiInterface(object):
    @classmethod
    def set_power(cls, url, on):
        ftdi = Ftdi()
        ftdi.open_from_url(url)
        # ... do other things with ftdi


...和测试文件

import unittest
from unittest import mock
from ftdi_interface import FtdiInterface
import pyftdi.ftdi

class TestFtdiInterface(unittest.TestCase):

    @mock.patch('pyftdi.ftdi.Ftdi')
    def testPowerOn(self, MockFtdi):
        url = 'some_string'
        ftdi_instance = mock.MagicMock()
        ftdi_instance.open_from_url = mock.MagicMock()
        MockFtdi.return_value = ftdi_instance

        FtdiInterface.set_power(url, True)
        ftdi_instance.open_from_url.assert_called_with(url)


我观察到的是,尽管我尝试修补Ftdi(),对ftdi_instance.open_from_url()的调用还是调用库代码,而不是我的模拟对象。

我想念什么?

最佳答案

Where to patch指出:


  基本原理是,您可以在查找对象的位置打补丁,而该对象不一定与定义对象的位置相同。


这意味着要mock一个类Ftdi,您必须提供一个路径,以指向代码中实际实例化Ftdi的位置。

为此,您需要将@mock.patch('pyftdi.ftdi.Ftdi')替换为@mock.patch('ftdi_interface.Ftdi')

import unittest
from unittest import mock
from ftdi_interface import FtdiInterface

class TestFtdiInterface(unittest.TestCase):

    @mock.patch('ftdi_interface.Ftdi')
    def testPowerOn(self, MockFtdi):
        url = 'some_string'
        ftdi_instance = mock.MagicMock()
        ftdi_instance.open_from_url = mock.MagicMock()
        MockFtdi.return_value = ftdi_instance

        FtdiInterface.set_power(url, True)
        ftdi_instance.open_from_url.assert_called_with(url)


import pyftdi.ftdi行对测试没有任何帮助,可以删除。

关于python - mock 一个类(class): catch 22,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49072847/

10-12 21:43