最终不会尝试对第一个失败的断言进行第二次断言
eventually doesn't attempt second assertion on first failed assertion
下面是一个简化的代码,用于了解最终的工作原理。
但它只尝试断言一次,最终不会尝试第二次断言。
package whisk_main
import org.scalatest.concurrent.Eventually.eventually
import org.scalatest.concurrent.Waiters.{interval, timeout}
import org.scalatest.flatspec.AsyncFlatSpecLike
import org.scalatest.matchers.should.Matchers
import org.scalatest.time.{Millis, Seconds, Span}
class EventuallySpec extends AsyncFlatSpecLike with Matchers{
"eventually" should "work, as expected" in {
val runnable = new Runnable {
override def run(): Unit = {
val currentThread = Thread.currentThread()
println(s"$currentThread starts here")
Thread.sleep(5000)
println(s"$currentThread ends here")
}
}
val threadThatSleepsForFiveSeconds = new Thread(runnable)
threadThatSleepsForFiveSeconds.start()
eventually(timeout(Span(15, Seconds)), interval(Span(2, Millis))) {
println("asserting thread state")
threadThatSleepsForFiveSeconds.getState should be(Thread.State.TERMINATED)
}
}
}
下面是异常跟踪:-
Thread[Thread-1,5,main] starts here
asserting thread state
TIMED_WAITING was not equal to TERMINATED
ScalaTestFailureLocation: whisk_main.EventuallySpec at (EventuallySpec.scala:28)
Expected :TERMINATED
Actual :TIMED_WAITING
<Click to see difference>
org.scalatest.exceptions.TestFailedException: TIMED_WAITING was not equal to TERMINATED
at org.scalatest.matchers.MatchersHelper$.indicateFailure(MatchersHelper.scala:344)
at org.scalatest.matchers.should.Matchers$ShouldMethodHelperClass.shouldMatcher(Matchers.scala:6778)
at org.scalatest.matchers.should.Matchers$AnyShouldWrapper.should(Matchers.scala:6822)
at whisk_main.EventuallySpec.$anonfun$new(EventuallySpec.scala:28)
我也尝试了下面的示例,该示例记录在 http://doc.scalatest.org/1.8/org/scalatest/concurrent/Eventually.html :-
val xs = 1 to 125
val it = xs.iterator
eventually { it.next should be (3) }
上面的例子在下面的例子中也失败了:-
1 was not equal to 3
ScalaTestFailureLocation: whisk_main.EventuallyExample at (EventuallyExample.scala:12)
Expected :3
Actual :1
<Click to see difference>
org.scalatest.exceptions.TestFailedException: 1 was not equal to 3
at org.scalatest.matchers.MatchersHelper$.indicateFailure(MatchersHelper.scala:344)
at org.scalatest.matchers.should.Matchers$ShouldMethodHelperClass.shouldMatcher(Matchers.scala:6778)
at org.scalatest.matchers.should.Matchers$AnyShouldWrapper.should(Matchers.scala:6822)
at whisk_main.EventuallyExample.$anonfun$new(EventuallyExample.scala:12)
请指教,为什么eventually一直不成功
您的问题是您正在扩展 AsyncFlatSpecLike
而您的测试是同步的。您观察到的行为是 AsyncFlatSpecLike
接受了您的每个测试的第一个断言,但失败了。将 class 声明更改为:
class EventuallySpec extends AnyFlatSpecLike with Matchers {
将使测试保持同步,并使您的测试通过,输出如下:
Thread[Thread-0,5,main] starts here
asserting thread state
asserting thread state
.
.
.
asserting thread state
asserting thread state
Thread[Thread-0,5,main] ends here
asserting thread state
如您所料。
如果您的测试确实是异步的,您还有另一个选择,那就是使用 AsyncFlatSpecLike
。例如,以下测试也通过了:
class MySpec extends AsyncFlatSpecLike with Matchers {
"eventually" should "work, as expected" in {
val runnable = new Runnable {
override def run(): Unit = {
val currentThread = Thread.currentThread()
println(s"$currentThread starts here")
Thread.sleep(5000)
println(s"$currentThread ends here")
}
}
val threadThatSleepsForFiveSeconds = new Thread(runnable)
threadThatSleepsForFiveSeconds.start()
eventually(timeout(Span(15, Seconds)), interval(Span(2, Millis))) {
println("asserting thread state")
Future {
Thread.sleep(10)
threadThatSleepsForFiveSeconds.getState must be(Thread.State.TERMINATED)
}
}
}
}
下面是一个简化的代码,用于了解最终的工作原理。 但它只尝试断言一次,最终不会尝试第二次断言。
package whisk_main
import org.scalatest.concurrent.Eventually.eventually
import org.scalatest.concurrent.Waiters.{interval, timeout}
import org.scalatest.flatspec.AsyncFlatSpecLike
import org.scalatest.matchers.should.Matchers
import org.scalatest.time.{Millis, Seconds, Span}
class EventuallySpec extends AsyncFlatSpecLike with Matchers{
"eventually" should "work, as expected" in {
val runnable = new Runnable {
override def run(): Unit = {
val currentThread = Thread.currentThread()
println(s"$currentThread starts here")
Thread.sleep(5000)
println(s"$currentThread ends here")
}
}
val threadThatSleepsForFiveSeconds = new Thread(runnable)
threadThatSleepsForFiveSeconds.start()
eventually(timeout(Span(15, Seconds)), interval(Span(2, Millis))) {
println("asserting thread state")
threadThatSleepsForFiveSeconds.getState should be(Thread.State.TERMINATED)
}
}
}
下面是异常跟踪:-
Thread[Thread-1,5,main] starts here
asserting thread state
TIMED_WAITING was not equal to TERMINATED
ScalaTestFailureLocation: whisk_main.EventuallySpec at (EventuallySpec.scala:28)
Expected :TERMINATED
Actual :TIMED_WAITING
<Click to see difference>
org.scalatest.exceptions.TestFailedException: TIMED_WAITING was not equal to TERMINATED
at org.scalatest.matchers.MatchersHelper$.indicateFailure(MatchersHelper.scala:344)
at org.scalatest.matchers.should.Matchers$ShouldMethodHelperClass.shouldMatcher(Matchers.scala:6778)
at org.scalatest.matchers.should.Matchers$AnyShouldWrapper.should(Matchers.scala:6822)
at whisk_main.EventuallySpec.$anonfun$new(EventuallySpec.scala:28)
我也尝试了下面的示例,该示例记录在 http://doc.scalatest.org/1.8/org/scalatest/concurrent/Eventually.html :-
val xs = 1 to 125
val it = xs.iterator
eventually { it.next should be (3) }
上面的例子在下面的例子中也失败了:-
1 was not equal to 3
ScalaTestFailureLocation: whisk_main.EventuallyExample at (EventuallyExample.scala:12)
Expected :3
Actual :1
<Click to see difference>
org.scalatest.exceptions.TestFailedException: 1 was not equal to 3
at org.scalatest.matchers.MatchersHelper$.indicateFailure(MatchersHelper.scala:344)
at org.scalatest.matchers.should.Matchers$ShouldMethodHelperClass.shouldMatcher(Matchers.scala:6778)
at org.scalatest.matchers.should.Matchers$AnyShouldWrapper.should(Matchers.scala:6822)
at whisk_main.EventuallyExample.$anonfun$new(EventuallyExample.scala:12)
请指教,为什么eventually一直不成功
您的问题是您正在扩展 AsyncFlatSpecLike
而您的测试是同步的。您观察到的行为是 AsyncFlatSpecLike
接受了您的每个测试的第一个断言,但失败了。将 class 声明更改为:
class EventuallySpec extends AnyFlatSpecLike with Matchers {
将使测试保持同步,并使您的测试通过,输出如下:
Thread[Thread-0,5,main] starts here
asserting thread state
asserting thread state
.
.
.
asserting thread state
asserting thread state
Thread[Thread-0,5,main] ends here
asserting thread state
如您所料。
如果您的测试确实是异步的,您还有另一个选择,那就是使用 AsyncFlatSpecLike
。例如,以下测试也通过了:
class MySpec extends AsyncFlatSpecLike with Matchers {
"eventually" should "work, as expected" in {
val runnable = new Runnable {
override def run(): Unit = {
val currentThread = Thread.currentThread()
println(s"$currentThread starts here")
Thread.sleep(5000)
println(s"$currentThread ends here")
}
}
val threadThatSleepsForFiveSeconds = new Thread(runnable)
threadThatSleepsForFiveSeconds.start()
eventually(timeout(Span(15, Seconds)), interval(Span(2, Millis))) {
println("asserting thread state")
Future {
Thread.sleep(10)
threadThatSleepsForFiveSeconds.getState must be(Thread.State.TERMINATED)
}
}
}
}