带有模拟的 Django 单元测试

Jer*_*eng 9 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
Run Code Online (Sandbox Code Playgroud)

关键问题是call_external_API()get_data().

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

我还可以get_data()通过仅对其进行单元测试并模拟call_external_API().

但是,当我测试整个基于类的视图时,我会这样做

self.client.get('/example/url/')
Run Code Online (Sandbox Code Playgroud)

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

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

Mic*_*ico 18

您正在寻找的是patch来自unittest.mock. 您可以call_external_api()MagicMock()对象进行修补。

也许您想为call_external_api()课堂上的所有测试打补丁。patch给你本质上两种方法来做到这一点

  • 装饰测试类
  • 分别使用start()and stop()in setUp()andtearDown()

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)
Run Code Online (Sandbox Code Playgroud)

可以构建更复杂的示例,您可以检查如何调用mock_call_external_api和设置 API 的返回值或副作用。

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

  1. 我假设在您的my_view模块中定义call_external_api或导入它,from my_API_module import call_external_api否则您应该注意在哪里打补丁
  2. 我用过autospec=True:恕我直言,它应该在每个补丁调用中使用,并且文档很好地解释了原因