Сегодня поговорим о тестировании. На изучение темы применительно к Go меня сподвигла задача минимизации HTML (подробнее в "Веб поиск на Go. Краулер. Как не хранить лишнее"). Реализация имела так много особых случаев, что без тестов удержать их в голове стало невозможно. А чуть позже природная лень сподвигла меня настроить автоматическую прогонку тестов.
GoConvey
Первое, что нужно сделать - бегло просмотреть документацию по доступному из коробки фреймворку тестирования Go и выбросить на помойку. Он настолько минималистичен (если хотите "недоделан"), что пользоваться им невозможно.
Относительно хорошим я бы назвал GoConvey, который от ему подобных отличается:
Для начала работы ставим пакет:
И в корне проекта запускаем:
Он сам отыщет модули с тестами, прогонит и откроет в браузере результат:
Синтаксис вопросов не вызывает:
Но лучше пролистать документацию, хотя бы для того, что бы узнать о вложенных тестах и о поддерживаемых видах assert'ов.
Так же фреймворк совместим со стандартными интерфейсами, поэтому "go test" отработает как нужно. В целом достаточно удобный и простой инструмент.
Относительно хорошим я бы назвал GoConvey, который от ему подобных отличается:
- Возможностью автоматически прогонять тесты при изменении файла.
- Наличием web интерфейса, который достаточно красочно показывает текущее состояние тестов.
- Иногда полезна возможность desktop нотификаций о результатах.
Для начала работы ставим пакет:
go get github.com/smartystreets/goconvey
goconvey
Синтаксис вопросов не вызывает:
package package_name import( "testing" . "github.com/smartystreets/goconvey/convey" ) func TestNum(t *testing.T) { Convey("1 should equal 1", t, func() { So(1, ShouldEqual, 1) }) }
Так же фреймворк совместим со стандартными интерфейсами, поэтому "go test" отработает как нужно. В целом достаточно удобный и простой инструмент.
Travis CI
Тесты мало написать, их нужно регулярно прогонять. Go конечно быстро компилирует тесты, а GoConvey автоматически их прогоняет, да и из редактора последние запускать не сложно. Но всё равно дисциплины на регулярный запуск не хватает, к тому же постоянная компиляция не слабо нагружает CPU.
А раз человек существо непостоянное и ленивое, переложим повторяющиеся действия на машину. Желательно на машину чужую. Тут поможет Travis, я о нём уже рассказывал, но тогда это был Rust, для Go - ещё проще. Настройка заключается в добавлении репозитория в отслеживаемые на travis-ci.org, плюс закомитить в корень проекта ".travis.yml":
Расшифровка:
А раз человек существо непостоянное и ленивое, переложим повторяющиеся действия на машину. Желательно на машину чужую. Тут поможет Travis, я о нём уже рассказывал, но тогда это был Rust, для Go - ещё проще. Настройка заключается в добавлении репозитория в отслеживаемые на travis-ci.org, плюс закомитить в корень проекта ".travis.yml":
language: go sudo: false go: - tip os: - linux install: - go get -u -t -v ./... script: - go build -v -o bin/go-web-search - ./go.test.sh after_success: - bash <(curl -s https://codecov.io/bash) notifications: email: recipients: - name@server.io on_success: never on_failure: always
- "language: go" - указываем какое окружение нам нужно, для Go будут добавлены cmake, scons и прочее.
- "go: - tip" - прогонять тесты будем только на последней версии Go, при желании можно явно указать другие.
- "sudo: false" - добровольно отказываемся от использования sudo, в ответ нам делают docker контейнер, который быстрее, выше, сильнее.
- секция "install" - ставим все зависимости проекта (и тестов - флаг "-t").
- в секции "script" - собственно собираем проект и потом запускаем тесты. Тесты можно было запустить командой "go test ./…", но мне нужно считать покрытие, ниже объясню зачем. Скрипт "go.test.sh" выглядит вот так.
- команда в after_success - триггер для codecov, о котором ниже.
- в "notifications" - рассылаем уведомление на почту, если сборка завершилась с ошибкой.
CodeCov
Твои тесты в Travis CI могут быть бесконечно зелёными, но какой в этом толк, если покрытие менее 100%? Самостоятельно постоянно мерить покрытие лень, забываешь. Это дело машин, они железные - стерпят. Хоть в Go и есть CLI утилиты для расчёта покрытия, но смотреть сухие цифры в консоли это одно, а красочно оформленные результаты совсем другое.
Codecov - замечательно решает эту проблему. Он наглядно показывает покрытие всего проекта целиком, отдельного файла, как изменялось покрытие после каждого комита и т.п. Плюс красивый интерактивный график. В общем смотрите сами.
Поддерживает 24 ЯП, бесплатен для Open Source и прост в настройке. Есть аналог coveralls.io, но визуально он мне нравится меньше. Для настройки, логинимся на codecov.io через аккаунт GitHub и добавляем репозиторий, он сам спросит нужные права и т.п. Потом добавляем в корень файл ".codecov.yml":
Это почти умолчательные настройки, где указываем кол-во знаков после запятой для покрытия, метод округления, цель к которой мы стремимся и т.п. Вот тут почитайте подробнее.
Далее ему необходим сформированный файл "coverage.txt" с указанием покрытия для каждого файла. Для этого тесты выше, я запускал через go.test.sh, который генерит всё необходимое. По завершению генерации файла, посылаем сигнал о том, что файл можно анализировать:
Выше я эту команду вызывал в Travis CI в секции "after_success". Всё! Осталось только добавить иконку в README с указанием покрытия. Документация тут.
Codecov - замечательно решает эту проблему. Он наглядно показывает покрытие всего проекта целиком, отдельного файла, как изменялось покрытие после каждого комита и т.п. Плюс красивый интерактивный график. В общем смотрите сами.
Поддерживает 24 ЯП, бесплатен для Open Source и прост в настройке. Есть аналог coveralls.io, но визуально он мне нравится меньше. Для настройки, логинимся на codecov.io через аккаунт GitHub и добавляем репозиторий, он сам спросит нужные права и т.п. Потом добавляем в корень файл ".codecov.yml":
coverage: precision: 2 round: nearest range: "40...90" status: project: default: target: "90%" threshold: "10%" patch: default: target: auto threshold: null changes: default: target: auto
Далее ему необходим сформированный файл "coverage.txt" с указанием покрытия для каждого файла. Для этого тесты выше, я запускал через go.test.sh, который генерит всё необходимое. По завершению генерации файла, посылаем сигнал о том, что файл можно анализировать:
bash <(curl -s https://codecov.io/bash)