【问题标题】:Testing actors using dependency injection in play framework 2.4.x在 play framework 2.4.x 中使用依赖注入测试 actor
【发布时间】:2015-12-16 15:47:06
【问题描述】:

如何测试依赖注入创建的actor?在我的应用程序中,我可以通过命名注入获得 ActorRef:

public MyClass {
    @Inject
    @Named("ping")
    ActorRef mPingRef;
}

如何在我的测试中获得此参考?

这是我的演员:

public class PingActor extends UntypedActor {
    @Inject
    public PingActor(Configuration configuration) {
         ... // Use config
    }


    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof Ping) {
            getSender().tell(new Pong(), getSelf());
        }
    }

    public static class Ping {}
    public static class Pong {}
}

我已经用我自己的模块配置了我的应用程序:

public class MyModule extends AbstractModule implements AkkaGuiceSupport {
    private final Configuration mConfig;

    public MyModule(Environment environment, Configuration configuration){
        this.mConfig = configuration;
    }

    @Override
    protected void configure() {
        bindActor(PingActor.class, "ping");
    }
}

模块在application.conf中启用:

play.modules.enabled += "com.my.package.MyModule"

【问题讨论】:

    标签: playframework akka guice playframework-2.4


    【解决方案1】:

    我正在编写actor单元测试

    static ActorSystem system;
    static Configuration configuration;
    static MyActor myActor;
    
    @BeforeClass
    public static void setup() {
        Map<String, Object> stringConf = new HashMap<>();
        configuration = new Configuration(stringConf);
    
        system = ActorSystem.apply();
        final Props props = Props.create(MyActor.class, configuration);
        final TestActorRef<MyActor> ref = TestActorRef.create(system, props, "myActor");
        myActor = ref.underlyingActor();
    }
    
    @AfterClass
    public static void teardown() {
        JavaTestKit.shutdownActorSystem(system);
        system = null;
    }
    

    然后你可以调用你的actor中的方法,就好像它是一个普通的java类一样。根据玩法框架https://www.playframework.com/documentation/2.5.x/JavaFunctionalTest

    通常最好的做法是仅在功能测试中注入成员并在单元测试中手动创建实例。

    这就是我在这里所做的。您将需要对

    的依赖
    "com.typesafe.akka" % "akka-testkit_2.11" % "2.4.12" % "test"
    

    为此工作。希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      此解决方案适用于PlayScala,但它应该与您的PlayJava 的机制相同:

      所以我得到了我的GuiceModule

      class CommonModule extends AbstractModule with AkkaGuiceSupport {
        override def configure(): Unit = {
          bindActor[SomeActor]("actor-name")
        }
      }
      

      然后是测试(我从测试中剥离了一些东西,所以它可能无法直接编译):

      import akka.actor.{ActorRef, ActorSystem}
      import akka.testkit.{TestKit, TestProbe}
      import module.CommonModule
      import org.specs2.mutable.Specification
      import org.specs2.specification.Scope
      import play.api.inject._
      import play.api.inject.guice.GuiceApplicationBuilder
      import play.api.test.Helpers._
      
      class SwitchUpdateActorSpec extends Specification {
      
        "MyActor" should {
      
          val actorSystem = ActorSystem("test")
          class Actors extends TestKit(actorSystem) with Scope
      
          val app = new GuiceApplicationBuilder(modules = Seq(new CommonModule))
            .overrides(bind[ActorSystem].toInstance(actorSystem))
            .build()
      
      
          "respond with 'ok' upon receiving a message" in new Actors {
            running(app) {
              private val injector: Injector = app.injector
              private val actor: ActorRef = injector.instanceOf(BindingKey(classOf[ActorRef]).qualifiedWith("actor-name"))
      
              val probe = TestProbe()
              actor.tell("hi there!", probe.ref)
      
              probe.expectMsg("ok")
            }
          }
        }    
      }
      

      所以我做的是:

      • 创建一个新鲜的ActorSystem
      • actorSystem 包裹在 Akka 的 TestKit (libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.4.1") 中
      • 使用GuiceApplicationBuilder 应用覆盖
      • 然后直接使用app.injector 来访问我的guice 配置的actor

      当您查看您在 MyModule.configure() 方法中使用的 bindActor 的实现时,很明显会发生什么:

        def bindActor[T <: Actor: ClassTag](name: String, props: Props => Props = identity): Unit = {
          accessBinder.bind(classOf[ActorRef])
            .annotatedWith(Names.named(name))
            .toProvider(Providers.guicify(Akka.providerOf[T](name, props)))
            .asEagerSingleton()
        }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 2016-02-26
        • 2015-09-30
        • 1970-01-01
        相关资源
        最近更新 更多