Пишите тонкие, быстрые и очевидные приемочные тесты с помощью Golang.

Что касается тестирования программного обеспечения, то разница между медленным тестом и тестом, которого не существует, невелика. Нет никакой разницы между тестом, который кто-то не знает, как запустить, и тестом, которого не существует. И более небрежно написать ломкий тест, чем вообще не написать тест. Хорошо — может быть, в этих утверждениях не хватает определенного нюанса, но в целом это три важных столпа качественного тестирования:

  • Тесты должны работать быстро
  • Тесты должны быть надежными
  • Тесты должны легко запускаться

Быстрый

Терпение — добродетель, но его следует систематизировать.

Скорость тестирования — понятие относительное. Например, интеграционный тест, который инициализирует виртуальную машину, почти наверняка займет больше времени, чем простой SpringBootTest.

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

Вот несколько простых оптимизаций:

  • Запускайте независимые тесты одновременно.
  • Настройте только то, что требуется, например. Тесты Spring Boot должны настраивать только необходимое подмножество компонентов Bean.
  • Перезапускать процессы и повторно инициализировать объекты только в том случае, если состояние загрязнено.

Крепкий

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

Хрупкие тесты очень быстро подрывают доверие. Хрупкий тест - это тест, который подвержен периодическим отказам. В идеале единственная причина, по которой тест должен провалиться, связана с критическим изменением функции, на которую вы ориентируетесь в тесте, например. блок кода.

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

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

Вот несколько простых улучшений:

  • Напишите логику, чтобы убедиться, что среда готова к тестированию. Если среда не готова, то этот тест следует пропустить, а не провалить, и в правильном сообщении об ошибке должно быть указано, почему среда не готова.
  • Избегайте условий гонки.
  • Будьте осторожны и очистите существующее состояние перед запуском теста. Это состояние могло быть испорчено из-за предыдущего теста или ручного вмешательства.
  • Будьте внимательны и убирайте загрязнённое состояние после каждого теста.

Простота

Тесты должны кодифицировать знания и облегчать их распространение.

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

Вторая часть систематизации опыта — сделать его легко доступным для ваших коллег и обеспечить, чтобы они могли легко его использовать. Например, для набора тестов может потребоваться Mongo. Пакет решил использовать встроенный Mongo? Если да, то надежно ли установить? Или, возможно, пакет требует реального экземпляра Mongo, работающего в докере. Знакомы ли ваши коллеги с Docker?

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

Гофер Жасмин

Gopher Jasmine — тестовая среда. В 511 строк кода он легко усваивается и может быть проверен на GitHub здесь. Он вдохновлен очевидным синтаксисом Jasmine, поэтому тесты написаны в похожем формате.

Посетите официальный веб-сайт для получения более подробных примеров и возможности запустить собственный набор тестов Gopher Jasmine.



Gopher Jasmine обращается к трем основным принципам, обсуждавшимся выше, а именно:

  • Тесты должны работать быстро
  • Тесты должны быть надежными
  • Тесты должны легко запускаться

Простой набор выглядит следующим образом:

Тесты должны работать быстро

Gopher Jasmine предлагает два типа люксов

1) Последовательный: тесты выполняются последовательно.

2) Одновременно: тесты выполняются параллельно.

Кроме того, вы получаете хорошую производительность, поскольку библиотека написана на Golang.

Тесты должны быть надежными

Gopher Jasmine предоставляет точки входа для настройки и демонтажа теста.

  • BeforeAll: выполнить логику один раз перед всем набором.
  • BeforeEach: выполнять логику перед каждым тестом.
  • AfterAll: выполнить логику один раз после всего набора.
  • AfterEach: выполнять логику после каждого теста.

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

Тесты должны легко запускаться

Есть много подобных и более мощных фреймворков, таких как Агути. Gopher Jasmine не собирается заменять эти фреймворки. Вместо этого Gopher Jasmine предоставляет тонкую, но полезную функцию:

Возможность запуска набора тестов во время выполнения.

По сути, фреймворк позволяет вам выставлять модульные/приемочные тесты через API, что упрощает запуск тестов. Один из моих любимых примеров такого подхода к тестированию во время выполнения — это мой телевизор Samsung. Одним нажатием кнопки я могу запустить набор тестов для проверки подключения к сети, хотя я ничего не знаю о том, что происходит внутри.

API для набора тестов можно создать с помощью одной строки.

Строка 14 загрузит сервер и выставит порт 9091. Разместите этот API локально или удаленно и используйте клиент для запуска наборов. Например, если вы запустите это локально, вы можете вызвать regression suite, выполнив следующий вызов:

$ curl http://localhost:9091/regression-suite

Вывод будет следующим:

Использование Gopher Jasmine в дикой природе

Мне удалось объединить Gopher Jasmine с конвейерами CICD. Представьте, что вам поручили разработать HTTP API, который создается и развертывается с помощью GitLab Pipelines. После развертывания любых изменений HTTP API очень полезно запустить приемочные тесты для их проверки. Пример конвейера выглядит так:

Вы можете настроить задание в конвейере для запуска Gopher Jasmine Regression Suite с помощью cURL. Проверьте выходные данные верхнего уровня ответа и завершите задание, если total_skipped или total_failed не равны нулю.