나는 현재 주어진 코드가 당황했는지 확인하는 테스트를 작성하는 방법을 고민하고 있습니다. 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
당황하고 우리가 회복 했는지 또는 기능이 전혀 당황하지 않았 는지 정말로 말할 수 없습니다 . 패닉이없는 경우 건너 뛸 코드와 패닉이있는 경우 실행할 코드를 어떻게 지정합니까? 회복 된 공황이 있었는지 어떻게 확인할 수 있습니까?
답변
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 시스템을 원하지 않더라도 .NET 과 함께 사용할 수있는 일치 라이브러리 인 Gomega 만 사용할 수 있습니다 testing
. 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()
}
답변
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을 확인하십시오 . 매우 간단한 주장과 모의.
답변
여러 테스트 케이스를 반복 할 때 다음과 같이 할 것입니다.
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)
}
})
}
}
답변
패닉의 내용을 확인해야 할 때 복구 된 값을 타입 캐스트 할 수 있습니다.
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)
}
테스트중인 코드가 당황하지 않거나 오류와 함께 당황하거나 예상 한 오류 메시지와 함께 당황하면 테스트가 실패합니다 (원하는 것임).
답변
귀하의 경우 다음을 수행 할 수 있습니다.
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
// ....
}
}
일반적인 패닉 라우터 기능으로 도 작동합니다.
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")
},
)
}
답변
간결한 방법
저에게 아래 솔루션은 읽기 쉽고 테스트중인 코드의 자연스러운 코드 흐름을 보여줍니다.
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")
}
보다 일반적인 솔루션의 경우 다음과 같이 할 수도 있습니다.
func TestPanic(t *testing.T) {
shouldPanic(t, OtherFunctionThatPanics)
}
func shouldPanic(t *testing.T, f func()) {
defer func() { recover() }()
f()
t.Errorf("should have panicked")
}
답변
패닉에 입력을 제공하여 패닉 된 기능을 테스트 할 수 있습니다.
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")
}
