Saat ini saya sedang memikirkan bagaimana menulis tes yang memeriksa apakah suatu kode panik? Saya tahu bahwa Go menggunakan recover
untuk menangkap kepanikan, tetapi tidak seperti kode Java, Anda tidak dapat benar-benar menentukan kode apa yang harus dilewati jika terjadi kepanikan atau apa yang Anda miliki. Jadi jika saya memiliki fungsi:
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")
}
Saya tidak bisa benar-benar tahu apakah OtherFunctionThatPanics
panik dan kami pulih, atau apakah fungsinya tidak panik sama sekali. Bagaimana cara menentukan kode mana yang harus dilewati jika tidak ada kepanikan dan kode mana yang harus dijalankan jika terjadi kepanikan? Bagaimana cara memeriksa apakah ada kepanikan yang kami pulihkan?
r := recover(); r == nil
dan tidak adilrecover() == nil
?Jika Anda menggunakan testify / assert , maka itu satu baris:
func TestOtherFunctionThatPanics(t *testing.T) { assert.Panics(t, OtherFunctionThatPanics, "The code did not panic") }
Atau, jika Anda
OtherFunctionThatPanics
memiliki tanda tangan selainfunc()
:func TestOtherFunctionThatPanics(t *testing.T) { assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic") }
Jika Anda belum mencoba bersaksi, lihat juga testify / mock . Pernyataan dan ejekan super sederhana.
sumber
Saat mengulang beberapa kasus uji, saya akan melakukan sesuatu seperti ini:
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) } }) } }
Pergilah bermain
sumber
Saat Anda perlu memeriksa konten kepanikan, Anda dapat mengetikkan nilai yang dipulihkan:
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) }
Jika kode yang Anda uji tidak panik ATAU panik dengan kesalahan ATAU panik dengan pesan kesalahan yang Anda harapkan, pengujian akan gagal (yang Anda inginkan).
sumber
Dalam kasus Anda, Anda dapat melakukan:
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 // .... } }
Sebagai fungsi router panik generik, ini juga akan berfungsi:
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") }, ) }
sumber
Cara Ringkas
Bagi saya, solusi di bawah ini mudah dibaca dan menunjukkan aliran kode alami dari kode yang diuji.
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") }
Untuk solusi yang lebih umum, Anda juga dapat melakukannya seperti ini:
func TestPanic(t *testing.T) { shouldPanic(t, OtherFunctionThatPanics) } func shouldPanic(t *testing.T, f func()) { defer func() { recover() }() f() t.Errorf("should have panicked") }
sumber
Anda dapat menguji fungsi mana yang panik dengan memberikan masukan kepada panik
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
sumber