Scala 最终不会';t在第一个失败的断言上尝试第二个断言

Scala 最终不会';t在第一个失败的断言上尝试第二个断言,scala,scalatest,Scala,Scalatest,下面是一个简化的代码,以了解最终是如何工作的。 但它只尝试一次断言,最终不会尝试第二次断言 package whisk_main import org.scalatest.concurrent.Eventually.eventually import org.scalatest.concurrent.Waiters.{interval, timeout} import org.scalatest.flatspec.AsyncFlatSpecLike import org.scalatest.m

下面是一个简化的代码,以了解最终是如何工作的。 但它只尝试一次断言,最终不会尝试第二次断言

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$2(EventuallySpec.scala:28)
上面的示例与下面的示例同样失败:-

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$2(EventuallyExample.scala:12)
1不等于3
ScalaTestFailureLocation:whisk_main.EventuallyExample at(EventuallyExample.scala:12)
预期:3
实际:1
org.scalatest.exceptions.TestFailedException:1不等于3
位于org.scalatest.matchers.matcherselper$.indicatatefailure(matcherselper.scala:344)
位于org.scalatest.matchers.should.matchers$ShouldMethodHelperClass.shouldMatcher(matchers.scala:6778)
位于org.scalatest.matchers.should.matchers$AnyShouldWrapper.should(matchers.scala:6822)
在whisk_main.EventuallyExample.$anonfun$new$2(EventuallyExample.scala:12)

请您提出建议,为什么最终要等到它成功后才能工作。

您的问题是,当您的测试是同步的时,您正在扩展
AsyncFlatSpecLike
。您观察到的行为是,
AsyncFlatSpecLike
接受每个测试的第一个断言,并失败。将类声明更改为:

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