简体   繁体   English

如何跳过失败的测试

[英]How to skip a failed test

In go, are you allowed skip a test that has already failed?在 go 中,您是否允许跳过已经失败的测试?

Context:语境:

I have a heisenbug which I cannot currently determine the cause of.我有一个heisenbug ,我目前无法确定其原因。 It causes some tests to sometimes fail.它有时会导致某些测试失败。 By examining various logs I can identify the failure mode.通过检查各种日志,我可以确定故障模式。 I would like to do something like:我想做类似的事情:

if t.Failed() {
    if strings.Contains(string(suite.Stdout), "connection reset by peer") {
        t.Skip("Skip Test failed ")
    }
}

The tests are valuable enough that I want to run them in CI despite the heisenbug so this is just a temporary workaround.这些测试非常有价值,尽管存在 heisenbug,我还是想在 CI 中运行它们,所以这只是一个临时的解决方法。

This doesn't work.这不起作用。 Is there a way to retrospectively skip a test if it fails?如果测试失败,有没有办法追溯跳过测试?

The short answer is no .简短的回答是否定的 You can skip a test or fail it but not both.您可以跳过测试或失败,但不能两者兼而有之。

The designers of go consider trying to skip a test as trying to subvert the test framework so you should not try to do this: go 的设计者认为尝试跳过测试是在尝试颠覆测试框架,因此您不应该尝试这样做:

See for example https://github.com/golang/go/issues/16502参见例如https://github.com/golang/go/issues/16502

This is documented but its easy to miss:这是有记录的,但很容易错过:

If a test fails (see Error, Errorf, Fail) and is then skipped, it is still considered to have failed.如果测试失败(参见 Error、Errorf、Fail)然后被跳过,它仍然被认为是失败的。

If you have a reliable way of detecting the heisenbug you should run it before making any test assertions.如果您有检测 heisenbug 的可靠方法,则应在进行任何测试断言之前运行它。 So rather than:所以而不是:

// execute
executeThingBeingTested()

// verify
assert.Equal(t, expected, actual)

// recover if needed
if t.Failed() {
    // detect heisenbug
    if strings.Contains(string(suite.Stdout), "connection reset by peer") {
        t.Skip("Skip Test failed ")
    }
}

You should instead structure your tests like:相反,您应该构建您的测试,例如:

// execute
executeThingBeingTested()

// skip if needed
if strings.Contains(string(suite.Stdout), "connection reset by peer") {
    t.Skip("Skip Test failed ")
}

// verify
assert.Equal(t, expected, actual)

This means that you cannot alternate between multiple execution and verification stages in a single test but its good practice to have only a single execution and verification stage in each test anyway.这意味着您不能在单个测试中的多个执行和验证阶段之间交替,但无论如何在每个测试中只有一个执行和验证阶段是一种很好的做法。 ie four phase testing四阶段测试

Now if you really really want to do it you can go low-level.现在,如果你真的想这样做,你可以去低级别的。 This is probably not a good idea but included for completeness.这可能不是一个好主意,但为了完整性而包括在内。 Peering down the rabbit hole may help show you don't want to go there.凝视兔子洞可能有助于表明您不想去那里。 This takes in consideration this question and how the testing package is implemented这考虑了这个问题以及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

If this level of hackery is not enough to convince you what a bad idea this is you might want to note the implementation of fail() at the time of writing:如果这种程度的黑客还不足以说服您这是一个多么糟糕的主意,那么您可能需要在撰写本文时注意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  }

You can see that as soon as Fail() is invoked any parent tests are also marked as having failed.您可以看到,一旦调用 Fail(),任何父测试也被标记为失败。 So if you are using something like testify/suite to organise tests into suites, to unfail a test you would also have to unfail the parent test but if and only if no other tests in the suite have failed.所以,如果你正在使用类似作证/套件来测试组织在若干套房,到unfail一个测试,你也必须unfail父测试,但是当且仅当在套房没有其他试验都失败了。 So altering the testing() package to allow skip to occur after fail interacts poorly with the idea of nested tests.因此,更改 testing() 包以允许在失败后发生跳过与嵌套测试的想法交互不佳。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM