Как использовать assert в тестах
Что проверяют
Знаете ли вы, что в стандартном пакете testing нет assert, и понимаете ли разницу между «продолжить тест» и «остановить тест» при провале проверки. Следом часто спрашивают, чем assert отличается от require в testify.
Как отвечать
Базовый способ без зависимостей: сравнить и вызвать t.Errorf (тест помечен проваленным и идёт дальше) или t.Fatalf (тест останавливается через t.FailNow). Во вспомогательных функциях ставят t.Helper(), чтобы строка ошибки указывала на вызывающий код, а не внутрь хелпера.
Для структур и срезов берут github.com/google/go-cmp/cmp: cmp.Diff(want, got) возвращает читаемый дифф, пустая строка означает равенство. Это удобнее reflect.DeepEqual, который отвечает только «да» или «нет».
Если в проекте testify:
assert.Equal(t, expected, actual): при провале пишет ошибку и возвращаетfalse, тест продолжается. Порядок аргументов важен: сначала ожидаемое, иначе сообщение будет путать;require.Equal: то же, но сt.FailNow(). Нужен, когда без проверки дальше смысла нет, напримерrequire.NoError(t, err)перед работой с результатом;assert.ErrorIs,assert.ElementsMatch,assert.JSONEq: ошибки по цепочкеerrors.Is, срезы без учёта порядка, JSON без учёта форматирования;assert.New(t): объект, чтобы не передаватьtв каждый вызов.
Проверки хорошо сочетаются с табличными тестами и t.Run: провал показывает имя конкретного случая.
Где спотыкаются
Вызывают require или t.Fatal из горутины, запущенной внутри теста. FailNow обязан вызываться из горутины самого теста, иначе останавливается только эта горутина, а тест живёт дальше. go vet ловит это проверкой testinggoroutine. Результат из горутины передают по каналу и проверяют в основном потоке.
Ставят assert там, где нужен require: после проваленной проверки err следующая строка разыменовывает nil, и паника прячет исходную причину.
Сравнивают числа с плавающей точкой через Equal вместо InDelta, а ошибки по тексту err.Error() вместо ErrorIs.