带模拟的 Django 单元测试
Django UnitTest with Mock
我正在为基于 Django class 的视图编写单元测试。
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
关键问题是 call_external_API()
在 get_data()
.
当我写单元测试的时候,我真的不想调用外部API来获取数据。首先,那会花我的钱;其次,我可以轻松地在另一个测试文件中测试 API。
我也可以通过仅对其进行单元测试并模拟 call_external_API()
.
的输出来轻松测试此 get_data()
方法
但是,当我测试整个基于 class 的视图时,我会做
self.client.get('/example/url/')
并检查状态代码和上下文数据以进行验证。
在这种情况下,当我测试整个基于 class 的视图时,如何模拟此 call_external_API()
?
在测试基于分类的视图时,您可以模拟 call_external_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
您要找的是patch
from unittest.mock
。您可以通过 MagicMock()
对象修补 call_external_api()
。
也许您想为 class 中的所有测试修补 call_external_api()
。 patch
给你两种基本的方法
- 装饰测试class
- 分别在
setUp()
和tearDown()
中使用start()
和stop()
用patch
装饰器装饰一个class就像装饰所有的测试方法一样(详见文档)实现起来会很整洁。按照示例假设您的视图在 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_call_external_api
并为您的 API 设置 return 值或副作用。
我没有给出任何关于启动和停止方式的例子(我不太喜欢)但我想花一些时间在两个 细节上 :
- 我假设在你的
my_view
模块中你定义了 call_external_api
或者你通过 from my_API_module import call_external_api
导入它否则你应该注意 Where to patch
- 我用过
autospec=True
:恕我直言,它应该在每个补丁调用中使用,documentation 很好地解释了为什么
我正在为基于 Django class 的视图编写单元测试。
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
关键问题是 call_external_API()
在 get_data()
.
当我写单元测试的时候,我真的不想调用外部API来获取数据。首先,那会花我的钱;其次,我可以轻松地在另一个测试文件中测试 API。
我也可以通过仅对其进行单元测试并模拟 call_external_API()
.
get_data()
方法
但是,当我测试整个基于 class 的视图时,我会做
self.client.get('/example/url/')
并检查状态代码和上下文数据以进行验证。
在这种情况下,当我测试整个基于 class 的视图时,如何模拟此 call_external_API()
?
在测试基于分类的视图时,您可以模拟 call_external_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
您要找的是patch
from unittest.mock
。您可以通过 MagicMock()
对象修补 call_external_api()
。
也许您想为 class 中的所有测试修补 call_external_api()
。 patch
给你两种基本的方法
- 装饰测试class
- 分别在
setUp()
和tearDown()
中使用start()
和stop()
用patch
装饰器装饰一个class就像装饰所有的测试方法一样(详见文档)实现起来会很整洁。按照示例假设您的视图在 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_call_external_api
并为您的 API 设置 return 值或副作用。
我没有给出任何关于启动和停止方式的例子(我不太喜欢)但我想花一些时间在两个 细节上 :
- 我假设在你的
my_view
模块中你定义了call_external_api
或者你通过from my_API_module import call_external_api
导入它否则你应该注意 Where to patch - 我用过
autospec=True
:恕我直言,它应该在每个补丁调用中使用,documentation 很好地解释了为什么