アクターをテストしているときに、アクターが予期せず (バグが原因で) 例外をスローするという状況が発生し、何度か噛まれましたが、テストは引き続きパスします。ほとんどの場合、アクターの例外は、テストが検証しているものは何でも適切に出力されないため、テストが失敗することを意味しますが、まれに、そうではない場合があります。例外はテスト ランナーとは別のスレッドで発生するため、テスト ランナーはそれについて何も知りません。
1 つの例として、依存関係が呼び出されることを確認するためにモックを使用しているときに、Actor コードのミスにより、モックで予期しないメソッドを呼び出す場合があります。これにより、モックはアクターを爆破する例外をスローしますが、テストは爆破します。アクターがどのように爆発したかが原因で、ダウンストリームテストが不可解に失敗することさえあります。例えば:
// using scala 2.10, akka 2.1.1, scalatest 1.9.1, easymock 3.1
// (FunSpec and TestKit)
class SomeAPI {
def foo(x: String) = println(x)
def bar(y: String) = println(y)
}
class SomeActor(someApi: SomeAPI) extends Actor {
def receive = {
case x:String =>
someApi.foo(x)
someApi.bar(x)
}
}
describe("problem example") {
it("calls foo only when it receives a message") {
val mockAPI = mock[SomeAPI]
val ref = TestActorRef(new SomeActor(mockAPI))
expecting {
mockAPI.foo("Hi").once()
}
whenExecuting(mockAPI) {
ref.tell("Hi", testActor)
}
}
it("ok actor") {
val ref = TestActorRef(new Actor {
def receive = {
case "Hi" => sender ! "Hello"
}
})
ref.tell("Hi", testActor)
expectMsg("Hello")
}
}
「problemExample」は成功しますが、下流の「okActor」は何らかの理由で失敗します。よくわかりません...次の例外があります。
cannot reserve actor name '$$b': already terminated
java.lang.IllegalStateException: cannot reserve actor name '$$b': already terminated
at akka.actor.dungeon.ChildrenContainer$TerminatedChildrenContainer$.reserve(ChildrenContainer.scala:86)
at akka.actor.dungeon.Children$class.reserveChild(Children.scala:78)
at akka.actor.ActorCell.reserveChild(ActorCell.scala:306)
at akka.testkit.TestActorRef.<init>(TestActorRef.scala:29)
したがって、afterEach ハンドラーのロガー出力を調べることで、この種のものをキャッチする方法を確認できます。確かに実行可能ですが、実際に例外が予想される場合は少し複雑で、それをテストしようとしています。しかし、これを処理してテストを失敗させる直接的な方法はありますか?
補遺: 私は TestEventListener を調べましたが、おそらく何か役立つものがあるのではないかと疑っていますが、それを見ることができません。私が見つけた唯一のドキュメントは、予期しない例外ではなく、予期される例外をチェックするためにそれを使用することに関するものでした。