github.com/MashinaMashina/api-tests

api-tests - утилита для автоматизированного тестирования REST API с поддержкой HTTP запросов и websocket соединений.


Keywords
api, json, rest, rest-api
Install
go get github.com/MashinaMashina/api-tests

Documentation

О проекте

api-tests - утилита для автоматизированного тестирования REST API с поддержкой HTTP запросов и websocket соединений.

Для кого

Для всех, кто хочет быть уверен что все методы его API работают как требуется.

Общее описание

Утилита на основе конфигурационных файлов отправляет запросы к серверу и сверяет ответ с заданным. Можно описывать последовательные запросы с передачей промежуточных данных.

Все настройки описываются в файлах в формате YAML, отдельный файл - отдельное действие. Файлы можно группировать в папки. Тесты в отдельных папках не зависят друг от друга, тесты в одной папке взаимосвязаны и сортируются между собой по имени файла.

В описаниях тестов доступны переменные, которые можно принимать из переменных окружения, из файла init.yml, либо создавать в процессе выполнения тестов.

Группы тестов

Отдельные тесты можно группировать помещая их в отдельную папку. Порядок запуска отдельных групп не регламентирован и может в будущем измениться.

Так же можно запускать выполнение только определенных групп по маске передавая параметр --pattern, в этом параметре можно указать регулярное выражение.

Например, может быть такая структура (тесты с проверкой логина и регистрации):

.
└── auth
    ├── login
    │   ├── 1-login.yml
    │   ├── 2-check-auth.yml
    │   └── init.yml
    └── register
        ├── 1-register.yml
        ├── 2-check-auth.yml
        └── init.yml

Пример запуска теста из папки auth/login: api-tests --pattern auth/login

Файл init

В папке с тестами можно создать файл init.yaml или init.yml. Этот файл обрабатывается перед запуском группы. В данный момент в файле можно только определить набор переменных для тестов - в секции store.

Пример файла init.yml с объявлением трех переменных:

store:
  host: localhost
  login: ivan
  password: qwrty123

Структура описания теста в файле

В файле теста могут быть несколько корневых секций:

  • name - имя теста. Обязательное поле.
  • request - http запрос к серверу.
  • response - валидация ответа http запроса.
  • receive - принятие сообщения из websocket канала.
  • message - валидация сообщения из websocket канала.

request

Секция описывает HTTP запрос к серверу.

Может содержать следующие параметры:

  • method - тип запроса (GET, POST, PUT...). По-умолчанию GET.
  • protocol - тип запроса: http или websocket. По-умолчанию http.
  • url - адрес запроса, например: https://www.google.com/search?q=tests или, в случае websocket соединения - wss://site.com/ws-open.
  • headers - список отправляемых заголовков.
  • body - тело запроса.
  • timeout - время ожидания ответа в секундах. По-умолчанию - 5.
  • channel - имя соединения. Websocket соединение сохраняется с этим именем и в будущем его можно использовать.

Пример файла с request. Отправляется POST запрос на адрес https://example.com/api/reports, в заголовках отправляется Content-Type: application/json, в теле запроса {"begin":1663099200000,"end":1663271999999}, время ожидания ответа - 30 секунд.

name: Отправляем POST запрос
request:
  method: POST
  url: 'https://example.com/api/reports'
  headers:
    Content-Type: application/json
  body: '{"begin":1663099200000,"end":1663271999999}'
  timeout: 30

response

Секция может состоять из нескольких элементов:

  • headers - валидация полученных заголовков - набор правил.
  • code - валидация кода ответа - набор правил. Всегда проверяется только числовой статус (200, 301, 404 и другие...).
  • body - валидация тела ответа - набор валидаторов

Валидатор

Валидатор регламентирует способ обращение к данным и правила, описывается параметрами type и rules. Параметр type может принимать значения из списка:

  • json - можно обращаться к элементам по ключу.
  • string - ответ сверяется как единое целое.

Параметр rules - это набор правил.

receive

Секция позволяет получать сообщение из вебсокет канала по фильтру. Имеет параметры:

  • channel - имя вебсокет соединения
  • timeout - время в секундах, сколько ждать сообщения
  • filter - набор валидаторов для фильтра. Сообщение считается подходящим, если ни один из фильтров не выдал ошибку.

message

Секция валидирует сообщение, которое было получено в receive. Содержит набор правил.

Правило

Правило описывается параметрами:

  • type - тип значения, которое проверяется (string, boolean, float, integer, jwt, hex, object, array)
  • key - ключ значения
  • equal - проверка значения на равенство
  • not-equal - проверка значения на не равенство
  • less - проверка на то, что значение меньше, чем указано
  • greater - проверка на то, что значение больше, чем указано
  • prefix - проверка на то, что значение содержит префикс
  • suffix - проверка на то, что значение содержит суффикс
  • required - указание на то что значение обязательно должно быть. По-умолчанию - true
  • store - сохранение значения с указанным именем
  • fields - правила для проверки вложенных значений (только для типов array и object)

Пример файла с валидацией ответа. Проверяется http код - должен быть 200 OK. Тело ответа проверяется как JSON. В ответе должны быть поля success типа boolean, в котором должно быть true, и поле data с JWT токеном, значение сохраняем в хранилище с именем token.

name: Авторизация
request:
  method: POST
  url: 'https://example-api.com/api/auth/login'
  headers:
    Content-type: application/json
  body: '{"username":"roman","password":"qwerty123"}'
response:
  code:
    - equal: 200
  body:
  - type: json
    rules:
      - key: success
        type: boolean
        equal: true
      - key: data
        type: JWT
        store: token

Еще пример с проверкой ответа на равенство.

name: Список пользователей
request:
  method: GET
  url: 'https://example-api.com/api/users'
response:
  body:
  - type: string
    rules:
      - equal: '["roman","ivan"]'

Пример с валидатором ответа как строка и проверкой того, что результат меньше, чем 10

name: Список пользователей
request:
  method: GET
  url: 'https://example-api.com/api/status'
response:
  body:
  - type: string
    rules:
      - type: integer
        less: 10

Валидация вложенных полей

Вложенные поля подерживаются только через валидатор json и с типами array и object.

Скажем некий API отдает такой ответ:

{
  "data": {
    "accounts": [
      {
        "name": "Ivan",
        "email": "ivan@mail.com"
      },
      {
        "name": "Roman",
        "email": "roman@mail.com"
      }
    ]
  }
}

Нам надо получить второй аккаунт и проверить имя. Это делается так:

# Имя теста
name: Получить второй аккаунт и проверить имя
# Отправляемый запрос
request:
  method: GET
  url: 'https://{{.TESTS_HOST}}/api/accounts'
# Валидация ответа
response:
  body:
  - type: json
    rules:
      # Обращаемся к data и получаем его как объект
      - key: data
        type: object
        fields:
          # Внутри data получаем accounts как массив
          - key: accounts
            type: array
            fields:
                # Получаем элемент по индексу 1 (второй элемент)
              - key: 1
                type: object
                fields:
                  # Получаем поле name как string, проверим что там текст Roman
                  - key: name
                    type: string
                    equal: Roman

К элементам массива можно обращаться по индексу, можно индекс не указывать - тогда пройдет валидация всех элементов массива.

Переменные

Во всех параметрах можно использовать переменные. Чтобы вставить значение переменной, вначале пишется {{., после имя переменной, и потом }}. Например {{.token}}.

Переменные можно обратиться к переменным окружения, но только к тем, имена которых начинаются на TESTS_.

Переменные можно определить в init файле, можно создавать во время выполнения указанием store у правила.

Переменные привязаны к группе тестов, это значит что внутри группы можно передавать данные между отдельными тестами, но не получится передавать данные между отдельными группами.

Пример двух файлов - в одном получаем токен, в другом используем. В тестах используем переменную окружения TESTS_HOST. В первом тесте создаем переменную token, во втором тесте - используем её.

1-auth.yml:

name: Авторизация
request:
  method: POST
  url: 'https://{{.TESTS_HOST}}/api/auth/login'
  body: '{"username":"roman","password":"qwerty123"}'
response:
  body:
  - type: json
    rules:
      - key: data
        type: JWT
        store: token

2-check-token.yml:

name: Авторизация
request:
  method: GET
  url: 'https://{{.TESTS_HOST}}/api/client/user/settings'
  headers:
    Authorization: 'Bearer {{.token}}'
response:
  body:
  - type: json
    rules:
      - key: success
        type: boolean
        equal: true