Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:单元测试中的模拟_Python_Unit Testing_Mocking - Fatal编程技术网

Python:单元测试中的模拟

Python:单元测试中的模拟,python,unit-testing,mocking,Python,Unit Testing,Mocking,我有类似的情况: class BaseClient(object): def __init__(self, api_key): self.api_key = api_key # Doing some staff. class ConcreteClient(BaseClient): def get_some_basic_data(self): # Doing something. def calculate(self):

我有类似的情况:

class BaseClient(object):
    def __init__(self, api_key):
        self.api_key = api_key
        # Doing some staff.

class ConcreteClient(BaseClient):
    def get_some_basic_data(self):
        # Doing something.

    def calculate(self):
        # some staff here
        self.get_some_basic_data(param)
        # some calculations
然后我想通过模拟
获取一些基本数据
函数来测试
计算
函数

我在做这样的事情:

import unittest
from my_module import ConcreteClient

def my_fake_data(param):
    return [{"key1": "val1"}, {"key2": "val2"}]

class ConcreteClientTest(unittest.TestCase):
    def setUp(self):
        self.client = Mock(ConcreteClient)

    def test_calculate(self):

        patch.object(ConcreteClient, 'get_some_basic_data',
                     return_value=my_fake_data).start()
        result = self.client.calculate(42)
但它并不像我想象的那样起作用。。正如我所想,
self.get_some_basic_data(param)
my_fake_data
函数返回我的列表,但它看起来仍然是一个模拟对象,这对我来说是不可能的


这里出了什么问题?

您在这里面临两个主要问题。引起您当前问题的主要原因是您实际上是如何嘲笑的。现在,由于您实际上正在为
ConcreteClient
修补
对象
,因此您需要确保您仍在使用真正的ConcreteClient,但在测试时模拟要模拟的实例的属性。您实际上可以在文档中看到此插图。不幸的是,没有明确的锚定线,但如果您遵循以下链接:

该节规定:

在使用patch()为您创建模拟的地方,您可以获得 使用with语句的“as”形式引用模拟:

参考代码为:

class ProductionClass:
    def method(self):
        pass

with patch.object(ProductionClass, 'method') as mock_method:
    mock_method.return_value = None
    real = ProductionClass()
    real.method(1, 2, 3)

mock_method.assert_called_with(1, 2, 3)
这里需要注意的关键事项是如何调用所有内容。请注意,类的真实实例已创建。在您的示例中,执行此操作时:

self.client = Mock(ConcreteClient)
您正在创建一个在客户机上指定的
Mock
对象。因此,最终这只是一个
Mock
对象,它保存
ConcreteClient
的属性。您实际上不会持有
ConcreteClient
的真实实例

解决这个问题。只需在修补对象后创建一个真实实例。此外,为了使您的生活更轻松,您不必手动启动/停止patch.object,请使用上下文管理器,它将为您节省大量的麻烦

最后,第二个问题是
返回值。您的
return\u值
实际上是在返回未调用的
my\u fake\u数据
函数。实际上,您需要数据本身,因此它需要是该函数的返回。您可以将数据本身作为
返回值

考虑到这两个更正,您的测试现在应该如下所示:

class ConcreteClientTest(unittest.TestCase):

    def test_calculate(self):

        with patch.object(ConcreteClient, 'get_some_basic_data',
                     return_value=[{"key1": "val1"}, {"key2": "val2"}]):

            concrete_client = ConcreteClient(Mock())
            result = concrete_client.calculate()

        self.assertEqual(
            result,
            [{"key1": "val1"}, {"key2": "val2"}]
        )
我冒昧地返回了
计算中的
获取一些基本数据的结果,只是为了比较一下。我不确定你真正的代码是什么样子的。但是,归根结底,你的测试结构,你应该如何做这一点,是说明了以上