在play framework 2.4.x中使用依赖注入测试actor

时间:2015-09-19 15:20:03

标签: playframework akka guice playframework-2.4

如何测试依赖注入创建的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"

2 个答案:

答案 0 :(得分:4)

此解决方案适用于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的TestKitlibraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.4.1"
  • 使用GuiceApplicationBuilder来应用覆盖
  • 然后直接使用app.injector访问我的guice配置的actor

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

  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()
  }

答案 1 :(得分:2)

我正在编写演员单元测试

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"

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