Тестирование модели Django с пользовательским методом сохранения, вызывающим внешний API - PullRequest
0 голосов
/ 07 ноября 2018

Я довольно новичок в юнит-тестах и ​​хочу сделать несколько "простых" тестов для начинающих в моем приложении 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 голосов
/ 07 ноября 2018

Это типичный пример использования библиотеки макетов 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 как декоратор, а также как менеджер контекста, если хотите смоделировать вызов функции в определенной части вашего кода. Подробнее см. Документацию .

Подробнее

В этом примере мы только издевались над методом, чтобы избежать создания вызываемого объекта. В некоторых случаях хорошей идеей может быть также проверка того, был ли вызван смоделированный метод и с какими аргументами.

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()

Последний вариант очень полезен для проверки того, что вы отправляете правильные данные во внешнюю службу. Подробнее о различных опциях в документации .

Почему насмешка над внешними звонками - хорошая идея

Хорошей идеей является прослушивание всех внешних вызовов, которые вы можете выполнять в своем наборе тестов. Вот несколько причин, почему:

  • Это улучшит производительность и скорость вашего набора тестов. Сетевые вызовы, как правило, требуют много времени, поэтому уменьшение количества вызовов ускорит тестирование.
  • Позволяет проверить данные, которые вы отправляете другим службам. Как видно из assert_called_once_with, вы можете утверждать, что однажды отправляете нужные данные другим службам
  • Это делает ваш набор тестов более предсказуемым. Используйте макеты, которые вы не будете полагаться на другие сервисы для тестирования вашего приложения. Время от времени внешние службы могут не отвечать должным образом (обслуживание, слишком много запросов и т. Д.). Используя mock, вы нарушите связь между вашим набором тестов и другими сервисами
  • Вы можете запускать тесты в автономном режиме (поездка, поезд, место и т. Д.).
...