简体   繁体   English

具有Mock的Django UnitTest

[英]Django UnitTest with Mock

I am writing an Unit-Test for a Django class-based view. 我正在为基于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

The key issue is that call_external_API() in get_data() . 关键问题是get_data()中的call_external_API() get_data()

When I am writing Unit-test, I don't really want to call external API to get data. 在编写单元测试时,我真的不想调用外部API来获取数据。 First, that will cost my money; 首先,这将花费我的钱; second, I can easily test that API in another test file. 其次,我可以轻松地在另一个测试文件中测试该API。

I also can easily test this get_data() method by having an unit-test only for it and mock the output of call_external_API() . 我也可以通过仅对其进行单元测试并模拟call_external_API()的输出来轻松测试此get_data()方法。

However, when I test this whole class-based view, I simply will do 但是,当我测试整个基于类的视图时,我只会做

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

and check the status code and context data to verify it. 并检查状态码和上下文数据以进行验证。

In this case, how do I mock this call_external_API() when I am testing the whole class-based view? 在这种情况下,当我测试整个基于类的视图时,如何模拟此call_external_API()

What your are looking for is patch from unittest.mock . 您正在寻找的是unittest.mock patch You can patch call_external_api() by a MagicMock() object. 您可以通过MagicMock()对象修补call_external_api()

Maybe you want to patch call_external_api() for all your tests in class. 也许您想为类中的所有测试修补call_external_api() patch give to you essentialy two way to do it patch为您提供了两种必备的方法

  • decorate the test class 装饰测试班
  • use start() and stop() in setUp() and tearDown() respectively 分别在setUp()tearDown()使用start()stop()

Decorate a class by patch decorator is like decorate all test methods (see documentation for details) and the implementation will be very neat. patch装饰器装饰类就像装饰所有测试方法(有关详细信息,请参见文档),实现将非常简洁。 Follow example assume that your view is in my_view module. 以下示例假定您的视图位于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)

More sophisticate examples can be build and you can check how you call mock_call_external_api and set return value or side effects for your API. 可以构建更多复杂的示例,并且可以检查如何调用mock_call_external_api并设置API的返回值或副作用。

I don't give any example about start and stop way to do it (I don't really like it) but I would like to spend some time on two details : 我没有提供任何有关启动和停止方式的示例(我不太喜欢),但是我想花一些时间在两个细节上

  1. I assumed that in your my_view module you define call_external_api or you import it by from my_API_module import call_external_api otherwise you should pay some attention on Where to patch 我假设您在my_view模块中定义了call_external_api或者通过from my_API_module import call_external_api导入了它,否则您应该注意在哪里打补丁
  2. I used autospec=True : IMHO it should be used in every patch call and documentation explain why very well 我使用了autospec=True :恕我直言,应该在每个补丁程序调用中使用它, 文档说明了为什么很好

You can mock the call_external_api() method when testing the classed based view with something like this: 在测试基于分类的视图时,可以使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM