Je me demande actuellement comment écrire des tests qui vérifient si un morceau de code donné a paniqué? Je sais que Go utilise recover
pour attraper les paniques, mais contrairement au code Java, vous ne pouvez pas vraiment spécifier quel code doit être ignoré en cas de panique ou ce que vous avez. Donc si j'ai une fonction:
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")
}
Je ne peux pas vraiment dire si OtherFunctionThatPanics
nous avons paniqué et nous avons récupéré, ou si la fonction n'a pas paniqué du tout. Comment spécifier le code à ignorer s'il n'y a pas de panique et quel code exécuter en cas de panique? Comment puis-je vérifier si nous nous sommes remis de la panique?
r := recover(); r == nil
et pas seulementrecover() == nil
?Si vous utilisez témoigner / affirmer , alors c'est une ligne unique:
func TestOtherFunctionThatPanics(t *testing.T) { assert.Panics(t, OtherFunctionThatPanics, "The code did not panic") }
Ou, si vous avez
OtherFunctionThatPanics
une signature autre quefunc()
:func TestOtherFunctionThatPanics(t *testing.T) { assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic") }
Si vous n'avez pas encore essayé de témoigner, consultez également témoigner / simuler . Assertions et moqueries super simples.
la source
Lors d'une boucle sur plusieurs cas de test, j'opterais pour quelque chose comme ceci:
package main import ( "reflect" "testing" ) func TestYourFunc(t *testing.T) { type args struct { arg1 int arg2 int arg3 int } tests := []struct { name string args args want []int wantErr bool wantPanic bool }{ //TODO: write test cases } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer func() { r := recover() if (r != nil) != tt.wantPanic { t.Errorf("SequenceInt() recover = %v, wantPanic = %v", r, tt.wantPanic) } }() got, err := YourFunc(tt.args.arg1, tt.args.arg2, tt.args.arg3) if (err != nil) != tt.wantErr { t.Errorf("YourFunc() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("YourFunc() = %v, want %v", got, tt.want) } }) } }
Aller au terrain de jeu
la source
Lorsque vous avez besoin de vérifier le contenu de la panique, vous pouvez taper la valeur récupérée:
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) }
Si le code que vous testez ne panique pas OU ne panique pas avec une erreur OU panique avec le message d'erreur que vous attendez, le test échouera (ce que vous voudriez).
la source
Dans votre cas, vous pouvez faire:
func f(t *testing.T) { recovered := func() (r bool) { defer func() { if r := recover(); r != nil { r = true } }() OtherFunctionThatPanics() // NOT BE EXECUTED IF PANICS // .... } if ! recovered() { t.Errorf("The code did not panic") // EXECUTED IF PANICS // .... } }
En tant que fonction de routeur panique générique , cela fonctionnera également:
https://github.com/7d4b9/recover
package recover func Recovered(IfPanic, Else func(), Then func(recover interface{})) (recoverElse interface{}) { defer func() { if r := recover(); r != nil { { // EXECUTED IF PANICS if Then != nil { Then(r) } } } }() IfPanic() { // NOT BE EXECUTED IF PANICS if Else != nil { defer func() { recoverElse = recover() }() Else() } } return } var testError = errors.New("expected error") func TestRecover(t *testing.T) { Recovered( func() { panic(testError) }, func() { t.Errorf("The code did not panic") }, func(r interface{}) { if err := r.(error); err != nil { assert.Error(t, testError, err) return } t.Errorf("The code did an unexpected panic") }, ) }
la source
Voie succincte
Pour moi, la solution ci-dessous est facile à lire et vous montre le flux de code naturel du code testé.
func TestPanic(t *testing.T) { // No need to check whether `recover()` is nil. Just turn off the panic. defer func() { recover() }() OtherFunctionThatPanics() // Never reaches here if `OtherFunctionThatPanics` panics. t.Errorf("did not panic") }
Pour une solution plus générale, vous pouvez également le faire comme ceci:
func TestPanic(t *testing.T) { shouldPanic(t, OtherFunctionThatPanics) } func shouldPanic(t *testing.T, f func()) { defer func() { recover() }() f() t.Errorf("should have panicked") }
la source
Vous pouvez tester quelle fonction a paniqué en donnant une entrée panique
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
la source