Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Testing 如何测试恐慌?_Testing_Go - Fatal编程技术网

Testing 如何测试恐慌?

Testing 如何测试恐慌?,testing,go,Testing,Go,我目前正在考虑如何编写测试来检查给定代码是否惊慌失措?我知道Go用于捕捉恐慌,但与Java代码不同,您不能真正指定在恐慌情况下应该跳过哪些代码,或者您已经完成了哪些。如果我有一个函数: func f(t *testing.T) { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() OtherFunct

我目前正在考虑如何编写测试来检查给定代码是否惊慌失措?我知道Go用于捕捉恐慌,但与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")
}
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()
}

我真的不知道其他函数是否惊慌失措,我们是否恢复了,或者函数是否完全没有惊慌失措。如何指定在没有死机时跳过哪些代码,以及在死机时执行哪些代码?如何检查我们是否恢复了一些恐慌?

您可以通过输入恐慌来测试哪个函数恐慌

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

}

测试实际上没有“成功”的概念,只有失败。所以你上面的代码是正确的。你可能会发现这种风格稍微清晰一些,但基本上是一样的

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()
}
我通常发现
测试
相当薄弱。您可能对更强大的测试引擎感兴趣,例如。即使您不想要完整的系统,也可以只使用它的matcher库,它可以与
测试一起使用。Gomega包括以下匹配器:

Expect(OtherFunctionThatPanics).To(Panic())
您还可以将紧急检查总结为一个简单的函数:

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

当您需要检查panic的内容时,可以键入恢复的值:

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 TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, OtherFunctionThatPanics, "The code did not panic")
}
或者,如果您的
otherfunctionthatparics
的签名不是
func()


如果你还没试过作证,那也去看看吧。超级简单的断言和模拟。

当在多个测试用例上循环时,我会选择如下方式:

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 f(t*testing.t){
已恢复:=func()(r bool){
延迟函数(){
如果r:=recover();r!=nil{
r=真
}
}()
OtherFunctionThatPanics()
//如果恐慌不被执行
// ....
}
如果!已恢复(){
t、 Errorf(“代码没有死机”)
//恐慌时被处决
// ....
}
}
作为一种通用紧急路由器功能,这也将起作用:

包恢复
func已恢复(IfPanic,Else func(),然后func(恢复接口{}))(恢复接口{}){
延迟函数(){
如果r:=recover();r!=nil{
{
//恐慌时被处决
如果那么!=零{
然后(r)
}
}
}
}()
IfPanic()
{
//如果恐慌不被执行
否则!=零{
延迟函数(){
recoverElse=recover()
}()
Else()
}
}
返回
}
var testError=errors.New(“预期错误”)
func TestRecover(t*testing.t){
恢复(
func(){
恐慌(测试错误)
},
func(){
t、 Errorf(“代码没有死机”)
},
func(r接口{}){
如果错误:=r.(错误);错误!=nil{
assert.Error(t、testError、err)
返回
}
t、 Errorf(“代码发生了意外的恐慌”)
},
)
}
惯用标准库解决方案 对我来说,下面的解决方案很容易阅读,并向维护人员展示了测试中的自然代码流。而且,它不需要第三方软件包

func TestPanic(t*testing.t){
//不需要检查'recover()'是否为零。只需关闭紧急状态。
延迟函数(){recover()}()
OtherFunctionThatPanics()
//如果“其他函数”恐慌,永远不要到达这里。
t、 Errorf(“没有惊慌”)
}

对于更通用的解决方案,您也可以这样做:

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 TestPanic(t*testing.t){
是否应使用PANIC(t,其他恐慌功能)
}
func shouldanic(t*testing.t,f func()){
延迟函数(){recover()}()
f()
t、 Errorf(“应该惊慌失措”)
}

以下是我的恐慌预期

func TestPanic(t*testing.t){
panicF:=func(){
//这里有紧急电话
}
需要。恐慌(t,恐慌)
}

对特定错误类型(如os.SyscallError)进行类型断言比比较错误消息(如从一个Go版本到下一个Go版本)更可靠。+Michael Aug,这可能是更好的方法,因为当有特定类型可用时。@IgorMikushkin在Go 1.11中,使用Rob Napier所描述的第一种形式实际上对覆盖范围有效;r==nil
,而不仅仅是
recover()==nil
?@DuncanJones在这种情况下不是真的。这是一种非常典型的Go模式,可以使错误在块中可用,因此OP可能习惯于这样编写(我将他的代码提前了),但在本例中没有实际使用。