I'm working on typed akka application and for some reason, I need to use untyped actors from typed context.
I wrote a simple test to try BehaviorTestKit and typed akka testkit. For typed actors it works but for an actor with untyped child I get "only adapted untyped ActorContext permissible " error.
Here is the parent actor:
public class AppGuardianTest extends AbstractBehavior<String> {
private ActorContext context;
public AppGuardianTest(ActorContext context) {
this.context = context;
ActorRef child = Adapter.actorOf(context, SomeUntypedActor.props(), "child");
}
@Override
public Receive<String> createReceive() {
return receiveBuilder()
.onMessage(String.class, m -> Behaviors.same())
.onSignal(PostStop.class, signal -> postStop()).build();
}
private Behavior<String> postStop() {
context.getLog().info("Application stopped");
return this;
}
public static Behavior behavior() {
return Behaviors.setup(AppGuardianTest::new);
}
}
The child actor
public class SomeUntypedActor extends AbstractActor {
public static Props props() {
return Props.create(SomeUntypedActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder().matchAny(m -> {
System.out.println(m);
}).build();
}
}
and the test
import akka.actor.testkit.typed.scaladsl.{BehaviorTestKit, ScalaTestWithActorTestKit}
import some.test.AppGuardianTest
import org.scalatest.WordSpecLike
class AppGuardianSpec extends ScalaTestWithActorTestKit with WordSpecLike {
"appGuardian" should {
"deploy child" in {
val testKit = BehaviorTestKit(AppGuardianTest.behavior())
val child = testKit.childInbox[String]("child")
}
}
}
Exception:
only adapted untyped ActorContext permissible (Inbox(Actor[akka.actor.typed.inbox://anonymous/testkit#1338528633]) of class akka.actor.testkit.typed.internal.EffectfulActorContext)
java.lang.UnsupportedOperationException: only adapted untyped ActorContext permissible (Inbox(Actor[akka.actor.typed.inbox://anonymous/testkit#1338528633]) of class akka.actor.testkit.typed.internal.EffectfulActorContext)
at akka.actor.typed.internal.adapter.ActorContextAdapter$.toUntypedImp(ActorContextAdapter.scala:110)
at akka.actor.typed.internal.adapter.ActorContextAdapter$.toUntyped(ActorContextAdapter.scala:125)
at akka.actor.typed.javadsl.Adapter$.actorOf(Adapter.scala:88)
at akka.actor.typed.javadsl.Adapter.actorOf(Adapter.scala)
at some.test.AppGuardianTest.<init>(AppGuardianTest.java:15)
at akka.actor.typed.javadsl.Behaviors$.$anonfun$setup$1(Behaviors.scala:43)
at akka.actor.typed.Behavior$DeferredBehavior$$anon$1.apply(Behavior.scala:239)
at akka.actor.typed.Behavior$.start(Behavior.scala:324)
...
The only way I have found is to use untyped akka TestKit instead of BehaviorTestKit. But you also need to store a link to a child somewhere, for instance in a static field (of course it cold be inappropriate in some situations)
"appGuardian" should {
"deploy child" in {
val AppG = Adapter.spawn(system, AppGuardianTest.behavior(), "app_g")
val actor = Await.result(Future {
while (AppGuardianTest.child == null) {
Thread.sleep(100)
}
AppGuardianTest.child
}(ExecutionContext.global), new FiniteDuration(5, TimeUnit.SECONDS))
}
}
I think it is not the best but one of the easiest way. Another way is to extend actor's protocol and add message with a child inside and ask AppGuardian for the child actor.
I have run into this same error. In the source code I have a typed actor and inside that one I want to spawn a classic actor. The child actor is being spawned from a classic system (this system was already in place) Writing the tests I was using the ScalaTestWithActorTestKit because I want to test a typed actor, but then the actor system being used is was typed one, when the source code expects a classic one. That's why going back to the classic testKit allows the test to work
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.