Как проверить панику?
В настоящее время я размышляю над тем, как писать тесты, которые проверяют, запанился ли данный фрагмент кода? Я знаю, что Go использует recover
, чтобы поймать панику, но, в отличие от, например, кода Java, вы не можете точно указать, какой код следует пропустить в случай паники или что у вас есть. Поэтому, если у меня есть функция:
func f(t *testing.T) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
OtherFunctionThatPanics()
t.Errorf("The code did not panic")
}
Я не могу сказать, паниковал ли OtherFunctionThatPanics
, и мы восстановились, или если функция не паниковала вообще. Как указать, какой код пропустить, если нет паники и какой код выполнить, если есть паника? Как я могу проверить, была ли какая-то паника, которую мы вызвали?
Ответы
Ответ 1
testing
действительно не имеет понятия "успех", только сбой. Таким образом, ваш код выше прав. Вы можете найти этот стиль немного более понятным, но это в основном то же самое.
func TestPanic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
// The following is the code under test
OtherFunctionThatPanics()
}
Я обычно нахожу testing
достаточно слабым. Вас могут заинтересовать более мощные двигатели для тестирования, такие как Ginkgo. Даже если вам не нужна полная система Гинкго, вы можете использовать только свою библиотеку-сопряжение, Gomega, которая может использоваться вместе с testing
. Гомега включает в себя такие как:
Expect(OtherFunctionThatPanics).To(Panic())
Вы также можете завершить проверку паники в простой функции:
func TestPanic(t *testing.T) {
assertPanic(t, OtherFunctionThatPanics)
}
func assertPanic(t *testing.T, f func()) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
f()
}
Ответ 2
Если вы используете testify/assert, то это однострочный:
func TestOtherFunctionThatPanics(t *testing.T) {
assert.Panics(t, OtherFunctionThatPanics, "The code did not panic")
}
Или, если ваш OtherFunctionThatPanics
имеет подпись, отличную от func()
:
func TestOtherFunctionThatPanics(t *testing.T) {
assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic")
}
Если вы не используете testify, то также проверьте testify/mock. Супер простые утверждения и макеты.
Ответ 3
Когда вам нужно проверить содержимое паники, вы можете придать возвращаемое значение:
func TestIsAheadComparedToPanicsWithDifferingStreams(t *testing.T) {
defer func() {
err := recover().(error)
if err.Error() != "Cursor: cannot compare cursors from different streams" {
t.Fatalf("Wrong panic message: %s", err.Error())
}
}()
c1 := CursorFromserializedMust("/foo:0:0")
c2 := CursorFromserializedMust("/bar:0:0")
// must panic
c1.IsAheadComparedTo(c2)
}
Если тестируемый код не вызывает панику или панику с ошибкой ИЛИ паники с сообщением об ошибке, которое вы ожидаете, тест завершится неудачно (это то, что вам нужно).
Ответ 4
Вы можете проверить, какая функция была проиндексирована, указав панику на вход
package main
import "fmt"
func explode() {
// Cause a panic.
panic("WRONG")
}
func explode1() {
// Cause a panic.
panic("WRONG1")
}
func main() {
// Handle errors in defer func with recover.
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok := r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
fmt.Println(err)
}
}
}()
// These causes an error. change between these
explode()
//explode1()
fmt.Println("Everything fine")
}
http://play.golang.org/p/ORWBqmPSVA