Функция тестирования, взаимодействующая с API Django Rest Framework с использованием библиотеки макетов python - PullRequest
0 голосов
/ 13 сентября 2018

Я хочу провести модульное тестирование модуля, взаимодействующего с API, созданным с помощью Django Rest Framework. Для этого я использую библиотеку Python Mock. Поскольку у меня нет опыта использования mocks для тестирования взаимодействия с API, у меня проблемы.

Функция, которая отправляет объект в конечную точку API, выглядит так (вкратце):

def send_experiment_to_portal(experiment: Experiment):
    rest = RestApiClient()

    if not rest.active:
        return None

    # general params
    params = {"nes_id": str(experiment.id),
              "title": experiment.title,
              "description": experiment.description,
              "data_acquisition_done":
                  str(experiment.data_acquisition_is_concluded),
              "project_url": experiment.source_code_url,
              "ethics_committee_url": experiment.ethics_committee_project_url
              }

    action_keys = ['experiments', 'create']

    portal_experiment = rest.client.action(
        rest.schema, action_keys, params=params,
    )

return portal_experiment

RestAPIClient - это класс, который аутентифицируется в API:

class RestApiClient(object):
    client = None
    schema = None
    active = False

    def __init__(self):
        auth = coreapi.auth.BasicAuthentication(
            username=settings.PORTAL_API['USER'],
            password=settings.PORTAL_API['PASSWORD']
        )
        self.client = coreapi.Client(auth=auth)

        try:
            url = settings.PORTAL_API['URL'] + \
                  (
                      ':' + settings.PORTAL_API['PORT'] if
                      settings.PORTAL_API['PORT'] else ''
                  ) \
                  + '/api/schema/'

            self.schema = self.client.get(url)
            self.active = True
        except:
            self.active = False

Класс RestApiClient использует клиентский модуль coreapi для подключения к API.

Итак, в конце я начинаю с проверки, имеет ли аргумент params в rest.client.action ключи / значения, которые предусмотрены API с использованием библиотеки python mock.

Я начинаю писать начальный тест как:

class PortalAPITest(TestCase):

    @patch('experiment.portal.RestApiClient')
    def test_send_experiment_to_portal(self, mockRestApiClientClass):
        research_project = ObjectsFactory.create_research_project()
        experiment = ObjectsFactory.create_experiment(research_project)

        result = send_experiment_to_portal(experiment)

Поэтому, когда я отлаживаю тест, заглядывая внутрь функции send_experiment_to_portal rest.client.action.call_args имеет значение:

call(<MagicMock name='RestApiClient().schema' id='139922756141240'>, ['expreiments', 'create'], params={'description': 'Descricao do Experimento-Update', 'ethics_committee_url': None, 'project_url': None, 'title': 'Experimento-Update', 'nes_id': '37', 'data_acquisition_done': 'False'})

Но mockRestApiClientClass.client.action.call_args имеет None. Я подозреваю, что я делаю неправильно. Я должен высмеивать rest.client.action, а не класс RestApiClient.

Попытка использовать result значение тоже не работает.

Значение результата

<MagicMock name='RestApiClient().client.action()' id='139821809672144'>

и result.call_args тоже None.

Но как это сделать? Как получить насмешливый rest экземпляр вне функции send_experiment_to_portal?

1 Ответ

0 голосов
/ 14 сентября 2018

После нескольких дней борьбы я смог найти решение.

Пересмешка RestApiClient возвращает макет класса, а не его значение, то есть значение переменной rest.Мы получаем значение rest, вызывающее return_value из фиктивного объекта.

Итак, мы должны вызвать mockRestApiClientClass.return_value вместо mockRestApiClientClass.

Выполнив это, мы имеем доступ кметоды и атрибуты rest, вызываемые изнутри send_experiment_end_message_to_portal, а затем mockRestApiClientClass.return_value.client.action.call_args будут иметь то же содержимое, что и наблюдаемое содержимое rest внутри send_experiment_end_message_to_portal контекста функции.

...