Одна из вещей, которые мне нравятся в Go, – это его стандартная библиотека, которая поставляется с батареями в комплекте. Конечно, некоторые пакеты (например, flag
) не такие мощные или эргономичные, как имеющиеся альтернативы, но я обычно готов с этим смириться, чтобы избежать зависимостей.
Тестирование
То же самое относится и к встроенной в Go поддержке тестирования, пакету testing
. Давайте рассмотрим типичный тест:
package example
import "testing"
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
want := 6
got := Add(4, 2)
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
}
Это не слишком плохо, но становится немного повторяющимся, поэтому люди часто используют внешние библиотеки утверждений, такие как testify
. Однако в большинстве своих проектов я стараюсь по возможности избегать внешних зависимостей, потому что не хочу заниматься их обновлением и тому подобной головной болью. Сегодня мне пришло в голову, что дженерики (добавленные в Go 1.18) позволяют легко писать полезные помощники утверждений, не прибегая к помощи библиотек. Вот помощник, который я добавил сегодня в один из своих проектов:
func assertEqual[T comparable](t *testing.T, got, want T) {
t.Helper()
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
}
Это утверждение равенства принимает параметр типа T
, который будет удовлетворяться любым типом, удовлетворяющим интерфейсу comparable
, определенному в блоке universe. Кроме того, он принимает три позиционных параметра: тестовый пример, а также фактическое и желаемое значения. Метод t.Helper()
гарантирует, что о неудачных утверждениях будет сообщено для строки, где используется assertEqual
, а не для строки внутри функции-помощника теста.
Вот как теперь выглядит тест:
package example
import "testing"
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
want := 6
got := Add(4, 2)
assertEqual(t, got, want)
// or simply
// assertEqual(t, Add(4, 2), 6)
}
Это не очень важно для одного теста, но заметно лучше для всего набора тестов.
Резюме
Использование новых дженериков Go позволило мне рефакторизовать и упростить набор тестов умеренно сложного проекта без необходимости добавления внешних зависимостей.