为了账号安全,请及时绑定邮箱和手机立即绑定

测试从恐慌中恢复

测试从恐慌中恢复

Go
慕神8447489 2021-10-25 18:15:28
我想测试一个构造函数,但如果没有提供一些数据,我需要恐慌,我如何在测试中从恐慌中恢复过来?目前我已经在我的 TestNew func 中添加了一个带有恢复的延迟,但如果我的地图中的元素具有空 URL,则不会检查其余元素。去package testingtype test {  url string}func New(ops map[string]string) *test {  if ops["url"] == "" {    panic("Url missing")  }  var t = new(test)  t.url = ops["url"]  return t}t_test.gopackage testingtype testTest map[string]stringvar testingTest = []testTest {  testTest {    "url": "test",  },  testTest{    "url": "",  },}func NewTest(t *testing.T) {  defer func() {    recover()  }()  for _, e := range testingTest {    url := New(e)    url.hasUrl(t, e["url"])  }}func (s *test) hasUrl(t *testing.T, u string) {  if s.url != u {    t.Errorf("Expected %s to be equal with %s", s.url, u)  }}
查看完整描述

3 回答

?
冉冉说

TA贡献1877条经验 获得超1个赞

我会说为依赖于恐慌/恢复的库设计 API 不是正确的方法。Go 有错误模式,所以如果 New 方法无法测试,它可以返回状态。


package testing


type test {

  url string

}


func New(ops map[string]string) (*test, bool) {

  if ops["url"] == "" {

    return nil, false

  }

  var t = new(test)

  t.url = ops["url"]

  return t, true

}

进而


for _, e := range testingTest {

  url, ok := New(e)

  if ok {

    url.hasUrl(t, e["url"])

  }

}

如果您坚持使用panic,那么您可以将调用包装到函数中并在其中恢复。但是你仍然需要向调用者提供状态。


package main


import "fmt"


func test(e int) {

    if e == 2 {

        panic("panic!")

    }

}


func main() {

    for _, e := range []int{1, 2, 3} {

        func() {

            defer func() { recover() }()

            test(e)

            fmt.Println("testing", e)

        }()

    }

}


查看完整回答
反对 回复 2021-10-25
?
三国纷争

TA贡献1804条经验 获得超7个赞

我对问题中的话感到困惑,但我认为它始于我同样的担忧。您已经定义了一个在违反前提条件时发生恐慌的函数,而不是替代方法(返回错误、使用默认值、什么都不做……);就像为数组做出的合理选择一样:


var a [1]int

a[1] = 0 // panic

有时您想编写一个测试来证明违反前提条件会导致恐慌并且不会被掩盖。前面的答案还不是很完整,所以这就是我所得到的:


func GreatBigFunction(url string) {

    if url == "" {

        panic("panic!")

    }

}


func main() {

    var tests = []struct {

        url       string

        completes bool

    }{

        {"a", true},

        {"", false},

        {"b", true},

        {"c", false}, // wrong expectation

        {"", true},   // wrong expectation

    }

    for _, test := range tests {

        fmt.Printf("testing that \"%s\" %s\n", test.url, map[bool]string{false: "panics", true: "completes"}[test.completes])

        func() {

            if !test.completes {

                defer func() {

                    p := recover()

                    if p == nil {

                        fmt.Println("t.Fail: should have panicked")

                    }

                }()

            }

            GreatBigFunction(test.url)

        }()

    }


    fmt.Println("Bye")

}

如果测试用例表明函数不应该恐慌,最后一个测试用例检查正常的恐慌处理是否有效。


相同的代码在 Playground 上。也可以忽略 的返回值recover但仍然可靠地报告丢失的panic。


查看完整回答
反对 回复 2021-10-25
  • 3 回答
  • 0 关注
  • 193 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信