4

http://doc.akka.io/docs/akka/snapshot/scala/testing.html#Using_Multiple_Probe_Actorsから例を拡張しました。

import akka.actor._
import akka.testkit.{TestProbe, TestKit}
import org.scalatest.{Suites, BeforeAndAfter, BeforeAndAfterAll, FlatSpecLike}
import scala.concurrent.duration._

class TestProbesTestSuites extends Suites(new TestProbesTest)

class TestProbesTest extends TestKit(ActorSystem("TestProbesTestSystem")) with FlatSpecLike with BeforeAndAfterAll with BeforeAndAfter {
  override def afterAll: Unit = {
    TestKit.shutdownActorSystem(system)
  }

  "A TestProbeTest" should "test TestProbes" in {
    val actorRef = system.actorOf(Props[TestActor], "TestActor")
    val tester1 = TestProbe()
    val tester2 = TestProbe()

    Thread.sleep(500.milliseconds.toMillis)

    actorRef ! (tester1.ref, tester2.ref)
    // When you comment the next line the test fails
    tester1.expectMsg(500.milliseconds, "Hello")
    tester2.expectMsg(500.milliseconds, "Hello")

    // Alternative test
//    Thread.sleep(500.milliseconds.toMillis)
//    tester1.expectMsg(0.milliseconds, "Hello")
//    tester2.expectMsg(0.milliseconds, "Hello")
    ()
  }
}

class TestActor extends Actor with ActorLogging {
  override def receive: Receive = {
    case (actorRef1: ActorRef, actorRef2: ActorRef) => {
      // When you change the schedule time in the next line to 100.milliseconds the test fails
      context.system.scheduler.scheduleOnce(400.milliseconds, actorRef1,  "Hello")(context.system.dispatcher)
      context.system.scheduler.scheduleOnce(800.milliseconds, actorRef2,  "Hello")(context.system.dispatcher)
    }
    case x => log.warning(x.toString)
  }
}

私は、これがテストのための正しい、または良い使い方だとは思いません。テストを削除するとtester1.expectMsg(500.milliseconds, "Hello")失敗するため、tester2 のテストは tester1 のテストに依存します。私の意見では、これは悪いことです。

また、回線context.system.scheduler.scheduleOnce(400.milliseconds, actorRef1, "Hello")(context.system.dispatcher)を 100 ミリ秒の遅延に変更すると、テストが失敗します。したがって、メッセージ 2 のテストは、メッセージ 1 の送信に依存します。私の意見では、これも悪いことです。

これを解決するには、メッセージの送信後に Thread.sleep を追加し、両方の #expectMsg の待機時間を 0 ミリ秒に変更します。Thread.sleep もテストでは良くないように見えますが、アクターのテストでは必須だと思います。これは正しい方法ですか?

TestProbe は複数のアクターをテストするために作られていると思いました。しかし、複数のアクターをテストする場合、#expectMsg の待機時間パラメーターはまったく役に立ちません。

どんな発言でも大歓迎です。

4

2 に答える 2

3

within代わりに、次のようにブロックを試すことができます。

within(800.milliseconds, 900.milliseconds){
  tester1.expectMsg("Hello")
  tester2.expectMsg("Hello")
}

tester1そうすれば、テストへのアサーションをコメントアウトしても合格します。

于 2015-08-04T13:51:16.373 に答える
2

テスト プローブは同期的に動作します。expectMsgメソッドがブロックされています。1 つのスレッドでテストを実行し、それを制御したいので、これは良いことです。このように競合状態はありません。

メッセージを待っている間のタイムアウトは、行が読み取られた時間から測定されます。つまり、500 ミリ秒は、メッセージを受信したtester2.expectMsg(500.milliseconds, "Hello")後にのみカウントダウンが開始されます。tester1

がメッセージを取得しない場合tester1は、すぐにテストを失敗させたいので、 に進む必要はありませんtester2

一方、スケジューラは複数のスレッドで非同期に実行され、ブロックがないためすぐにカウントダウンが開始されます。したがって、スケジュールされた 400 ミリ秒と 800 ミリ秒は (ほぼ) 同時にカウントダウンを開始します。

したがって、400 ミリを 100 ミリに変更すると、2 番目のメッセージは開始から約 800 ミリ送信されますが、開始からtester1100 + 500 = 600 ミリになると予想されます。それが失敗する理由です。

于 2015-08-04T12:51:09.807 に答える