Django单元测试和模拟测试

13

我正在为一个基于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

关键问题在于get_data()中的call_external_API()

当我编写单元测试时,我不想真的调用外部API来获取数据。首先,那会花我的钱;其次,我可以在另一个测试文件中轻松地测试该API。

我还可以通过为get_data()方法编写一个单元测试,并模拟call_external_API()的输出来轻松测试此方法。

但是,当我测试整个基于类的视图时,我只需执行以下操作

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

并检查状态码和上下文数据以验证其正确性。

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


不确定你两种情况的区别在哪里。为什么不能以同样的方式模拟它? - Daniel Roseman
2个回答

23
你需要的是来自unittest.mockpatch。你可以用一个MagicMock()对象来修补call_external_api()
也许你想为类中的所有测试修补call_external_api()patch提供了两种方法:
  • 装饰测试类
  • setUp()tearDown()中使用start()stop()
通过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
这就是我要找的答案。谢谢! - Jerry Meng

3

当使用类视图测试时,您可以模拟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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接