Тестирование актеров с использованием внедрения зависимостей в игровой среде 2.4.x

Как протестировать актера, созданного путем внедрения зависимостей? В моем приложении я могу получить 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"

person jorgenfb    schedule 19.09.2015    source источник


Ответы (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 в TestKit Акки (libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.4.1")
  • используйте GuiceApplicationBuilder, чтобы применить переопределение
  • а затем используйте app.injector напрямую, чтобы получить доступ к моему актеру, сконфигурированному с помощью guice

Становится совершенно очевидным, что происходит, когда вы смотрите на реализацию 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()
  }
person mana    schedule 10.12.2015

Я пишу модульные тесты актеров как таковые

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;
}

затем вы можете вызывать методы в своем актере, как если бы это был обычный класс Java. Согласно игровой структуре https://www.playframework.com/documentation/2.5.x/JavaFunctionalTest

Как правило, лучше всего вводить элементы только в функциональных тестах и ​​вручную создавать экземпляры в модульных тестах.

так вот что я здесь делаю. Вам понадобится зависимость от

"com.typesafe.akka" % "akka-testkit_2.11" % "2.4.12" % "test"

чтобы это работало. Надеюсь это поможет.

person m1416    schedule 02.11.2016