我的情况类似于:
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
然后我想使用模拟calculate
函数来测试get_some_basic_data
函数。
我正在做这样的事情:
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
函数返回我的列表,但看起来它仍然是一个Mock对象,这对我来说是不可取的
这里有什么问题?
答案 0 :(得分:1)
您在这里遇到两个主要问题。引发当前问题的主要问题是因为 你实际上是在嘲笑。现在,由于您实际上正在为object
修补ConcreteClient
,因此您需要确保仍在使用真实 ConcreteClient但模拟测试时要模拟的实例的属性。您实际上可以在文档中看到此插图。不幸的是,确切的行没有明确的锚点,但是如果你按照这个链接:
https://docs.python.org/3/library/unittest.mock-examples.html
指出的部分:
如果你使用patch()为你创建一个模拟,你可以得到一个 使用with语句的“as”形式引用mock:
参考代码为:
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)
您正在ConcreteClient上创建 specced 的Mock
对象。因此,最终这只是一个Mock
对象,其中包含ConcreteClient
的属性。您实际上不会持有ConcreteClient
的真实实例。
解决这个问题。在修补对象后,只需创建一个真实的实例。此外,为了让您的生活更轻松,您不必手动启动/停止patch.object,使用上下文管理器,它将为您节省很多麻烦。
最后,您的第二个问题是return_value
。您的return_value
实际上正在返回未被调用的 my_fake_data
函数。您实际上想要数据本身,因此它需要是该函数的 return 。您可以将数据本身作为return_value
。
考虑到这两个更正,您的测试现在应该如下所示:
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"}]
)
我冒昧地在get_some_basic_data
中返回calculate
的结果,只是为了有一些东西要比较。我不确定您的真正的代码是什么样的。但是,最终,您的测试结构如何应该如此,如上所述。