Python Django单元测试与模拟
我正在为基于Django类的视图编写一个单元测试Python Django单元测试与模拟,python,django,unit-testing,mocking,Python,Django,Unit Testing,Mocking,我正在为基于Django类的视图编写一个单元测试 class ExampleView(ListView): def get_context_data(self, **kwargs): context = super(EampleView, self).get_context_data(**kwargs) ## do something else def get_queryset(self, **kwargs): ret
class ExampleView(ListView):
def get_context_data(self, **kwargs):
context = super(EampleView, self).get_context_data(**kwargs)
## do something else
def get_queryset(self, **kwargs):
return self.get_data()
def get_data(self):
call_external_API()
## do something else
关键问题是在get\u data()
中调用\u external\u API()
当我编写单元测试时,我真的不想调用外部API来获取数据。首先,这将花费我的钱;其次,我可以在另一个测试文件中轻松测试该API
我还可以简单地测试这个get\u data()
方法,只对它进行单元测试,并模拟call\u external\u API()
的输出
然而,当我测试整个基于类的视图时,我只会这样做
self.client.get('/example/url/')
并检查状态代码和上下文数据以进行验证
在这种情况下,当我测试整个基于类的视图时,如何模拟此
调用\u external\u API()
。在测试基于类的视图时,可以模拟调用\u external\u API()
方法,如下所示:
import modulea
import unittest
from mock import Mock
class ExampleTestCase(unittest.TestCase):
def setUp(self):
self.call_external_api = modulea.call_external_api
def tearDown(self):
modulea.call_external_api = self.call_external_api
def get_data(self):
modulea.call_external_api = Mock(return_value="foobar")
modulea.call_external_api()
## do something else
你要找的是。您可以通过
MagicMock()
对象修补调用\u external\u api()
也许您想为类中的所有测试修补调用\u external\u api()
<代码>补丁基本上提供两种方法
- 装饰测试类
- 分别在
和setUp()
tearDown()中使用
和start()
stop()
patch
decorator装饰一个类就像装饰所有的测试方法一样(详细信息请参见文档),实现将非常简洁。下面的示例假设您的视图位于my_view
模块中
@patch("my_view.call_external_api", autospec=True)
class MyTest(unittest.TestCase):
def setUp(self):
self.client = Client()
def test_get_data(self, mock_call_external_api):
self.client.get('/example/url/')
self.assertTrue(mock_call_external_api.called)
可以构建更复杂的示例,您可以检查如何调用mock\u call\u external\u api
,并为api设置返回值或副作用
我没有给出任何关于启动和停止方式的例子(我真的不喜欢),但我想花一些时间讨论两个细节:
my\u视图
模块中定义call\u external\u api
或通过从my\u api\u模块导入call\u external\u api
导入它,否则您应该注意autospec=True
:IMHO应该在每个补丁调用中使用它,并很好地解释了原因不确定你的两个场景有什么不同。你为什么不能用同样的方式来嘲笑它呢?这就是我想要的答案。非常感谢。