Как измерить покрытие тестами (code coverage) в Go?
Основы измерения покрытия в Go
Go предоставляет встроенную поддержку измерения покрытия кода тестами без установки сторонних инструментов. Всё, что вам нужно — это стандартная утилита go test с соответствующими флагами.
1. Простой процент покрытия
Самый простой способ — запустить тесты с флагом -cover:
go test -cover
Вывод будет выглядеть примерно так:
ok your-module 0.002s coverage: 75.0% of statements
Если хотите видеть покрытие для каждого пакета отдельно, используйте -coverprofile для сохранения отчёта:
go test -coverprofile=coverage.out
go tool cover -func=coverage.out
Вторая команда покажет таблицу с покрытием каждой функции:
your-module/main.go:8: handler 100.0%
your-module/main.go:12: TestHandler 100.0%
total: (statements) 100.0%
2. Просмотр непокрытых строк
Чтобы увидеть, какие конкретно строки кода не покрыты тестами, сгенерируйте HTML-отчёт:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out -o coverage.html
Откройте файл coverage.html в браузере. Зелёным цветом будут отмечены покрытые строки, красным — непокрытые. Серым — строки, которые не участвуют в анализе (например, объявления пакетов).
3. Практический пример с вашим кодом
Предположим, у вас есть файл main.go с обработчиком и тест в main_test.go:
// main.go
package main
import "net/http"
func handler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
w.Write([]byte("Hello, World!"))
} else {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
// main_test.go
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHandler_GET(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
handler(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("expected 200, got %d", rr.Code)
}
}
Запустим с отчётом:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
В HTML-отчёте вы увидите, что ветка else (обработка POST/PUT и т.д.) подсвечена красным — она не покрыта тестом. Это подскажет вам написать второй тест:
func TestHandler_POST(t *testing.T) {
req := httptest.NewRequest("POST", "/", nil)
rr := httptest.NewRecorder()
handler(rr, req)
if rr.Code != http.StatusMethodNotAllowed {
t.Errorf("expected 405, got %d", rr.Code)
}
}
Важные нюансы
- Покрытие считается только для выполняемых строк. Объявления типов, констант и импортов не учитываются.
- Флаг
-covermodeопределяет режим:set(по умолчанию, просто проверяет, выполнялась ли строка),count(сколько раз выполнялась),atomic(для параллельных тестов). - Для больших проектов используйте
go test ./...чтобы прогнать тесты во всех пакетах рекурсивно. - Не гонитесь за 100% покрытием. Хороший ориентир — 70-80% для бизнес-логики. Главное — покрыть критические пути и граничные случаи.
Теперь вы можете легко оценивать качество тестирования и находить "слепые зоны" в коде!
<<Альтернативный подход: использование сторонних инструментов
Стандартный инструмент go tool cover отлично справляется с базовыми задачами, но для более продвинутого анализа можно использовать gocover или go-test-coverage.
Пример с gocover (установка: go install github.com/axw/gocov/gocov@latest):
# Запуск с профилем
go test -coverprofile=coverage.out
# Анализ через gocov
gocov convert coverage.out | gocov report
Этот инструмент показывает покрытие в более читаемом текстовом формате с разбивкой по пакетам и функциям.
Для CI/CD (например, GitLab CI или GitHub Actions) удобно использовать go-test-coverage:
go install github.com/vladopajic/go-test-coverage@latest
go-test-coverage --config=./.testcoverage.yml
Он позволяет задать порог покрытия и выдавать ошибку, если порог не достигнут. Пример конфига:
profile: coverage.out
threshold:
file: 70
package: 80
total: 85
Если вам нужно визуализировать покрытие прямо в редакторе, установите расширение для VS Code Go Cover — оно подсвечивает непокрытые строки прямо в коде.
Помните: любой инструмент — лишь помощник. Главное — писать осмысленные тесты, а не гнаться за цифрами.
Ответов пока нет.
Войдите чтобы оставить ответ