web-dev-qa-db-ja.com

パニックをテストするには?

現在、特定のコードがパニック状態になっているかどうかを確認するテストを作成する方法を検討していますか? 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がパニックして回復したかどうか、または関数がまったくパニックにならなかったかどうかはわかりません。パニックがない場合にスキップするコードと、パニックがある場合に実行するコードを指定するにはどうすればよいですか?パニックが回復したかどうかを確認するにはどうすればよいですか?

62
ThePiachu

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 のような、より強力なテストエンジンに興味があるかもしれません。完全なGinkgoシステムが必要ない場合でも、testingとともに使用できるマッチャーライブラリ Gomega のみを使用できます。 Gomegaには、次のようなマッチャーが含まれています。

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()
}
76
Rob Napier

testify/assert を使用すると、1行になります。

_func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, OtherFunctionThatPanics, "The code did not panic")
}
_

または、OtherFunctionThatPanicsfunc()以外の署名がある場合:

_func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic")
}
_

まだ証言していない場合は、 testify/mock も確認してください。超シンプルなアサーションとモック。

21
Jacob Marble

複数のテストケースをループする場合、次のようなものを探します。

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)
            }
        })
    }
}

遊び場に行く

3
Aleh

パニックの内容を確認する必要がある場合、回復した値を型キャストできます。

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)
}

テストしているコードがパニックしない場合ORエラーでパニックOR期待するエラーメッセージでパニックすると、テストは失敗しますあなたが望むものです)。

2
joonas.fi

パニックを入力することで、どの機能がパニックしたかをテストできます

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

0
Thellimist