Django UnitTest与模拟

时间:2015-03-02 18:54:09

标签: 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):
         return self.get_data()

     def get_data(self):
         call_external_API()
         ## do something else

关键问题是call_external_API()中的get_data()

当我编写单元测试时,我真的不想调用外部API来获取数据。首先,这将耗费我的钱;第二,我可以在另一个测试文件中轻松测试该API。

我也可以通过仅对其进行单元测试并模拟get_data()的输出来轻松测试此call_external_API()方法。

然而,当我测试这个基于类的整个视图时,我只会做

self.client.get('/example/url/')

并检查状态代码和上下文数据以进行验证。

在这种情况下,当我测试整个基于类的视图时,如何模拟此call_external_API()

2 个答案:

答案 0 :(得分:1)

您正在寻找的是patch from unittest.mock。您可以通过call_external_api()对象修补MagicMock()

也许您想在课堂上为所有测试修补call_external_api()patch向你提供两种方式来实现它

  • 装饰测试类
  • 分别在start()stop()中使用setUp()tearDown()

装饰一个类patch装饰器就像装饰所有测试方法(详见文档),实现非常简洁。以下示例假设您的视图位于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设置返回值或副作用。

我没有提供任何关于开始和停止方式的例子(我不太喜欢)但我想花一些时间在两个细节上

  1. 我认为您在my_view模块中定义call_external_api或者按from my_API_module import call_external_api导入它,否则您应该注意Where to patch
  2. 我使用autospec=True:恕我直言,它应该在每个补丁调用中使用,documentation解释为什么非常好

答案 1 :(得分:0)

在使用类似的方法测试基于分类的视图时,您可以模拟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