Комментарии 18
Замечательная идея.
Благодарю, что нашли время оформить и поделиться.
Schemathesis as a Service. Мы работаем над тем, чтобы всё было в один клик. Просто вводим адрес схемы и всё замечательно тестируется, не надо писать никакого кода.
Первая реакция по ходу чтения - сделать тестер/валидатор доступным как сервис.
Подписался.
Сервис планируется сделать коммерческим или будут другие опции?
Например, я бы заплатил и использовал в своих API.
Скажите прямо - Schemathesis лучше, чем Dredd? :)
На мой предвзятый взгляд - да. С точки зрения поиска дефектов Schemathesis дает намного больше возможностей чем Dredd. В основном за счет использования Property-Based тестирования и генерации данных даже если примеров в схеме нет. Так же Schemathesis полноценно поддерживает Open API 3 (в Dredd поддержка эксперементальная). Конечно, Dredd умеет какие-то вещи которые Schemathesis не умеет. Например поддержка API Blueprint и хуков на разных языках. В FAQ можно почитать немного более развернутое сравнение.
Если говорить о сравнении эффективности на реальных проектах, то можно посмотреть эксперименты одной из статей для ICSE 2022. Сама статья должна быть опубликована в декабре. Эксперименты включают тестирование различных приложений с Open API схемами через Dredd, Schemathesis и еще несколько проектов. Они измеряют покрытие кода в приложениях, ошибки в коде и т.д. Например в одном из экспериментов Schemathesis покрыл 65% кода (в строчках) бэкенда, а Dredd 38%. В некоторых примерах разница меньше, но в целом, в этих экспериментах Schemathesis показал больший или примерно такой же процент покрытия чем Dredd, даже учитывая тот факт, что использовалась довольно старая версия Schemathesis в которой еще не было негативного тестирования.
Спасибо за тексты ошибок. Скорее всего там под капотом тоже используется валидация JSON Schema, только отдается конкретная ошибка из leaf узла где есть additionalProperties: false
. В то время когда в jsonschema отдается ошибка из узла самого близкого к корню (т.е. oneOf
). Скорее всего это можно будет решить легче чем я думал изначально, просто выбрав другую ошибку из дерева которое возвращает jsonschema :)
В данный момент Schemathesis использует jsonschema для валидации схем и выводит ошибку оттуда напрямую. Я однозначно хочу это улучшить - для этого есть отдельный issue (довольно долго уже висит). Вполне вероятно что будет проще написать валидацию напрямую чем использовать ошибки из jsonschema (которые особенно неприятно разбирать из-за того древовидной структуры ошибок которую эта библиотека отдаёт).
Я постараюсь вернуться к этой проблеме в ближайшее время.
Отдельно хочу сказать что эту валидацию можно отключить (--validate-schema=false
), если нужно запустить тесты без учета валидности схемы.
EDIT: Ответ на комментарий выше
@Stranger6667 Пробую использовать ваш инструмент и время от времени получаю ошибку Hypothesis при чтении создаваемой в тесте сущности:
Falsified on the first call but did not on a subsequent one
Насколько я понял, это присходит, когда Hypothesis делает проверку при двух последовательно идущих одинковых запросах. Он ожидает, что ответ будет одинаковым (проверка идемпотентности), но в теле ответа меняется идентификатор сущности и он считает это ошибкой. Я понимаю, что вопрос не совсем по адресу, но может быть вы подскажете как сделать эту проверку корректно? Или как отключить проверку идемпотентности для этого конкретного теста.
В целом такое происходит из-за того что когда Hypothesis сталкивается с падением теста, он пытается удостовериться что ошибка надежно воспроизводится. Если у него не получается, то он выводит это сообщение об ошибке.
Насколько я понял, это присходит, когда Hypothesis делает проверку при двух последовательно идущих одинковых запросах. Он ожидает, что ответ будет одинаковым (проверка идемпотентности), но в теле ответа меняется идентификатор сущности и он считает это ошибкой
С учетом встроенных проверок, различающиеся идентификаторы не должны вызывать проблему если они оба соответствуют схеме. Но я думаю, что в целом у вас верное понимание ситуации (особенно об идемпотентности)!
Чаще всего такое поведение связано с тем что внутреннее состояние тестируемого сервиса отличается в начале каждого "теста" (это может быть и последовательность запросов, если рассматривать stateful тестирование). Например, если имена сущностей в сервисе должны быть уникальные, то:
Запрос на создание сущности с именем Test, пришел 201й ответ несоответствующий схеме, но в сервисе сущность успешно создалась. Hypothesis зарегистрировал ошибку.
Hypothesis пытается воспроизвести эту ошибку отправляя такой же запрос как в предыдущем пункте. Получает 409 который уже соответствует схеме - предыдущая ошибка не воспроизводится
но может быть вы подскажете как сделать эту проверку корректно?
БОльшая часть такого рода проблем решается очисткой состояния приложения перед каждым тестом. В CLI это можно сделать при помощи хука before_call, в Python тестах через использования контекстного менеджера в теле теста (как рекомендуется в документации Hypothesis).
В зависимости от сложности тестируемого сервиса, добавление логики для очистки состояния может сильно замедлить тесты, но результаты будет легче воспроизвести.
Или как отключить проверку идемпотентности для этого конкретного теста
В данный момент, это логику напрямую не отключить, но я планирую сделать такую возможность (возможно даже включить это по-умолчанию)
Надеюсь, что мой комментарий поможет вам :)
@Stranger6667 В документации Schemathesis есть раздел Examples in API schemas в котором написано, что тэг example поддерживается. Т. е. позитивные тесты должны формироваться на основе примеров из схемы. Но у меня они почему-то не используются, хотя в схеме заданы. В результате из схемы автоматически генерируются только негативные тесты, а позитивыне кейсы мне приходится указывать явно в тестах. Пробовал задавать примеры в конкрентом свойстве модели в схеме, но результат тот же. Тесты пишу в pytest. Для "включения" примеров из схемы в тест-кейсы нужно как-то указать это явно? Не могли бы вы показать это на примере?
Возможно это важно: схема использует OpenAPI v. 2.0
В Open API 2.0 ключ "example" используется в меньшем количестве мест, по сравнению с 3.0, а именно в schemaObject и fileSchema. Причем для генерации тестов можно использовать только первый. Schemathesis поддерживает "example" только в таких случаях для Open API 2.0, чтобы следовать спецификации.
Но! Поддерживаются расширения "x-example" и "x-examples" для всех мест где определены соответствующие "example" и "examples" из Open API 3.0.
Т.е. это может выглядеть так (я убрал некоторые части для краткости)
{
"swagger": "2.0",
"paths": {
"/query": {
"get": {
"parameters": [
{
"name": "id",
"in": "query",
"required": true,
"type": "string",
"x-example": "test"
}
]
}
}
}
}
Документацию обновлю, действительно там не очень явно эта ситуация описана.
P.S. Для более быстрой обратной связи, возможно будет проще использовать мой телеграм
Использование API-схем для property-based-тестирования