使用调用外部API的自定义保存方法测试Django模型

时间:2018-11-07 10:25:54

标签: django django-unittest

我对单元测试非常陌生,并且想在我的Django应用程序中进行一些“简单”的初学者测试,我有一个带有“自定义”保存方法的模型,如果有新方法,它将调用外部api。无法在不调用外部API的情况下弄清楚如何建立该模型,该如何实现模拟解决方案?

class Task(models.Model):
    status = models.CharField(max_length=25, choices=STATUS_CHOICES, default='new')
    ....

    def _create(self):
        ....
        return requests.post(API_URL + url, json=payload).json()

    def save(self, *args, **kwargs):
        is_new = self.created is None
        super(Task, self).save(*args, **kwargs)

        if is_new:
            self._create()

class TaskTestCase(TestCase):

    def setUp(self):

        self.task = Task.objects.create(status='new')

    def test_get_new_task(self):
        task = Task.objects.all()[0]
        self.assertEqual(task.status, 'new')

1 个答案:

答案 0 :(得分:3)

这是python模拟库的典型用例。在您的情况下,我可能看起来像这样

import mock
class TaskTestCase(TestCase):

    @mock.patch("request.post")
    def setUp(self, mocked_post):

        self.task = Task.objects.create(status='new')

    def test_get_new_task(self):
        task = Task.objects.all()[0]
        self.assertEqual(task.status, 'new')

如果要在代码的特定部分上模拟函数调用,则可以将mock.patch用作装饰器,也可以用作上下文管理器。 See the documentation for more details

更多详细信息

在此示例中,我们仅嘲笑了该方法,以避免真正进行调用。在某些情况下,最好检查是否已调用模拟方法以及使用哪个参数。

import mock
class TaskTestCase(TestCase):

@mock.patch("request.post")
def setUp(self, mocked_post):

    self.task = Task.objects.create(status='new')
    # The most basic way to check a call was performed
    mocked_post..assert_called() 

    # Checking the number of call can be a good idea
    mocked_post.assert_called_once()

    # Same idea but it also checks the arguments of the method.
    mocked_post.assert_called_once_with()

最后一个选项对于测试您是否正在向外部服务发送正确的数据非常有用。有关不同选项in the documentation的更多详细信息。

为什么嘲笑外部调用是个好主意

模拟您可以在测试套件中进行的所有外部呼叫确实是一个好主意。原因如下:

  • 它将提高测试套件的性能和速度。网络通话通常很耗时,减少通话数量将加快测试套件的速度。
  • 它允许您测试要发送到其他服务的数据。如assert_call_once_with所示,您可以断言一旦向其他服务发送了正确的数据
  • 这使您的测试套件更加可预测。使用不依赖任何其他服务的模拟程序来测试您的应用程序。外部服务有时可能无法正确响应(维护,太多请求等)。使用模拟,您将打破测试套件与其他服务之间的联系
  • 您可以离线运行测试(上下班,训练,放置等)。