猿问

如何跳过失败的测试

在进行中,您是否可以跳过已经失败的测试?


语境:


我有一个heisenbug,我目前无法确定其原因。它会导致某些测试有时会失败。通过检查各种日志,我可以识别故障模式。我想做类似的事情:


if t.Failed() {

    if strings.Contains(string(suite.Stdout), "connection reset by peer") {

        t.Skip("Skip Test failed ")

    }

}

这些测试非常有价值,我想在 CI 中运行它们,尽管有 heisenbug,所以这只是一个临时的解决方法。


这行不通。如果测试失败,有没有办法追溯跳过测试?


catspeake
浏览 128回答 1
1回答

FFIVE

简短的回答是否定的。您可以跳过测试或失败,但不能两者兼而有之。Go 的设计者认为试图跳过测试是试图颠覆测试框架,所以你不应该尝试这样做:参见例如https://github.com/golang/go/issues/16502这是记录在案的,但很容易错过:如果测试失败(参见 Error、Errorf、Fail)然后被跳过,它仍然被认为是失败的。如果您有可靠的方法来检测 heisenbug,您应该在做出任何测试断言之前运行它。所以而不是:// executeexecuteThingBeingTested()// verifyassert.Equal(t, expected, actual)// recover if neededif t.Failed() {    // detect heisenbug    if strings.Contains(string(suite.Stdout), "connection reset by peer") {        t.Skip("Skip Test failed ")    }}相反,您应该像这样构建测试:// executeexecuteThingBeingTested()// skip if neededif strings.Contains(string(suite.Stdout), "connection reset by peer") {    t.Skip("Skip Test failed ")}// verifyassert.Equal(t, expected, actual)这意味着您不能在单个测试中的多个执行和验证阶段之间交替,但是无论如何在每个测试中只有一个执行和验证阶段是一种很好的做法。即四阶段测试现在,如果你真的 很想做,你可以去低级。这可能不是一个好主意,但为了完整性而包括在内。凝视兔子洞可能有助于表明你不想去那里。这考虑了这个问题以及如何实现testing包    t := suite.T()    // low-level hackery - undo the failed state so we can skip a test    pointerVal := reflect.ValueOf(t)    val := reflect.Indirect(pointerVal)    member := val.FieldByName("failed")    ptrToFailedFlag := unsafe.Pointer(member.UnsafeAddr())    realPtrToFailedFlag := (*bool)(ptrToFailedFlag)    *realPtrToFailedFlag = false如果这种级别的黑客技术不足以说服您这是一个多么糟糕的主意,您可能需要fail()在撰写本文时注意实现:        // Fail marks the function as having failed but continues execution.   605  func (c *common) Fail() {   606      if c.parent != nil {   607          c.parent.Fail()   608      }   609      c.mu.Lock()   610      defer c.mu.Unlock()   611      // c.done needs to be locked to synchronize checks to c.done in parent tests.   612      if c.done {   613          panic("Fail in goroutine after " + c.name + " has completed")   614      }   615      c.failed = true   616  }您可以看到,一旦调用 Fail(),任何父测试也被标记为失败。因此,如果您使用testify/suite之类的东西将测试组织成套件,unfail那么您还必须unfail使用父测试,但当且仅当套件中没有其他测试失败时。因此,更改 testing() 包以允许在失败后发生跳过与嵌套测试的想法的交互性很差。
随时随地看视频慕课网APP

相关分类

Go
我要回答