akka 最终没有容忍不成功的尝试才放弃

xdnvmnnf  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(194)

我有一个简单的测试用例,它使用TestActorRef并最终验证一个方法的超时调用。下面是3个文件源的详细信息:

测试REST实用程序.scala

import play.api.http.HttpVerbs
import play.api.libs.ws.WSClient

import javax.inject.Inject
import scala.concurrent.Future

class TestRestUtility @Inject()(ws: WSClient) extends HttpVerbs {

  import scala.concurrent.ExecutionContext.Implicits.global

  def getHealthStatus(): Future[Int] = {
    ws.url("https://www.google.com").get().map { response =>
      response.status
    }
  }

}

测试运行状况检查执行元.scala

import akka.actor.{Actor, ActorLogging, Props}
import play.api.http.Status

import javax.inject.Inject
import scala.concurrent.Future
import scala.concurrent.duration.{DurationInt, FiniteDuration}
import scala.util.{Failure, Success}

object TestHealthCheckActor {
  def props(testRestUtility: TestRestUtility): Props = {
    Props(new TestHealthCheckActor(testRestUtility: TestRestUtility))
  }
}

class TestHealthCheckActor @Inject()(testRestUtility: TestRestUtility)
  extends Actor with ActorLogging with Status {

  import context.dispatcher

  val checkPeriod: FiniteDuration = 1.seconds
  var apiStatus: Int = _

  override def preStart(): Unit = {
    context.system.scheduler.scheduleWithFixedDelay(
      0.milliseconds,
      checkPeriod,
      self,
      RefreshHealthStatus
    )
  }

  override def receive: Receive = {
    case RefreshHealthStatus =>
      val health: Future[Int] = testRestUtility.getHealthStatus()

      health.onComplete({
        case Success(result) =>
          result match {
            case OK => apiStatus = Status.OK
            case _ => apiStatus = Status.REQUEST_TIMEOUT
          }
        case Failure(e) =>
          println(e)
      })
  }
}

测试规格等级

import akka.actor.{ActorSystem, PoisonPill}
import akka.testkit.{ImplicitSender, TestActorRef, TestKit}
import org.mockito.Mockito
import org.mockito.Mockito.{times, verify, when}
import org.scalatest
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach}
import org.scalatest.concurrent.Eventually
import org.scalatest.matchers.should.Matchers
import org.scalatest.time.Span
import org.scalatest.wordspec.AnyWordSpecLike
import org.scalatestplus.mockito.MockitoSugar
import play.api.http.Status

import scala.concurrent.Future

class TestSpec extends TestKit(ActorSystem("HealthCheckActorSpec")) with AnyWordSpecLike with Matchers
with BeforeAndAfterEach with MockitoSugar with ImplicitSender with Eventually with BeforeAndAfterAll with Status with TestHarnessConstants {

  import scala.concurrent.ExecutionContext.Implicits.global

  var mockTestRestUtility: TestRestUtility = _

  "HealthCheckActor" should {    
    "time out and call subscription api" in {
      mockTestRestUtility = mock[TestRestUtility]
      when(mockTestRestUtility.getHealthStatus()).thenReturn(Future(OK)).thenReturn(Future(OK)).thenReturn(Future(OK))
      val healthCheckActorShortPeriod: TestActorRef[TestHealthCheckActor] = TestActorRef(TestHealthCheckActor.props(mockTestRestUtility))

      eventually(timeout(Span(9, scalatest.time.Seconds)), interval(Span(1, scalatest.time.Seconds))) {
        verify(mockTestRestUtility, Mockito.atLeast(3)).getHealthStatus()
      }

      healthCheckActorShortPeriod ! PoisonPill
    }
  }
}

如“scalast-core_2.12-3.2.3-sources.jar”中关于最终的描述,它在放弃之前容忍不成功的尝试,因此测试用例预期有3次调用方法**getHealthStatus()**以成功作为mock的返回值。但我得到了一个失败的测试用例,并显示以下错误消息。我不知道为什么该方法只被调用了一次:

testRestUtility.getHealthStatus();
Wanted *at least* 3 times:
-> at com.deere.isg.ingest.supporttool.testharness.TestSpec.$anonfun$new$8(TestSpec.scala:44)
But was 1 time:
-> at com.deere.isg.ingest.supporttool.testharness.TestHealthCheckActor$$anonfun$receive$1.applyOrElse(TestHealthCheckActor.scala:36)

org.mockito.exceptions.verification.TooFewActualInvocations: 
testRestUtility.getHealthStatus();
Wanted *at least* 3 times:
-> at com.deere.isg.ingest.supporttool.testharness.TestSpec.$anonfun$new$8(TestSpec.scala:44)
But was 1 time:
-> at com.deere.isg.ingest.supporttool.testharness.TestHealthCheckActor$$anonfun$receive$1.applyOrElse(TestHealthCheckActor.scala:36)
6g8kf2rb

6g8kf2rb1#

eventually将认为Future(OK)成功,因为它不会抛出异常(从技术上讲,失败的Future也不会抛出异常,除非您在eventually中将其解包)。由于第一次调用成功,eventually在第一次调用之后不会再进行任何尝试。

相关问题