2015-09-19 29 views
6

Come si esegue il test di un attore creato dall'integrazione delle dipendenze? Nella mia applicazione posso ottenere un ActorRef con un'iniezione denominata:Test degli attori che utilizzano l'iniezione delle dipendenze nel framework di gioco 2.4.x

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

Come si ottiene questo riferimento nei test?

Questo è il mio attore:

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

ho configurato la mia applicazione con il mio modulo:

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

Il modulo è attivata in application.conf:

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

risposta

4

Questo soluzione è per PlayScala, ma dovrebbe essere lo stesso meccanismo per il tuo PlayJava:

Così ho ottenuto il mio GuiceModule:

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

Poi il test (ho messo a nudo alcune cose dal mio test, quindi non può compilare direttamente):

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

Quindi quello che ho fatto è stato:

  • creare una nuova ActorSystem
  • avvolgere che actorSystem a TestKit (libraryDependencies += "com.typesafe.akka" %% "akka-testkit" % "2.4.1")
  • uso di Akka il GuiceApplicationBuilder per applicare l'override
  • e quindi usare il app.injector direttamente per ottenere l'accesso al mio Guice configurato attore

diventa abbastanza evidente che cosa succede, quando si guarda in attuazione bindActor che si sta utilizzando nel metodo 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() 
    } 
2

Im unit test di scrittura attore in quanto tali

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

quindi è possibile chiamare i metodi nel tuo attore, come se si trattasse di una classe Java regolare. Secondo il framework di gioco https://www.playframework.com/documentation/2.5.x/JavaFunctionalTest

In genere è consigliabile iniettare i membri solo nei test funzionali e creare manualmente le istanze nei test di unità.

questo è quello che sto facendo qui. Avrete bisogno di una dipendenza su

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

affinché funzioni. Spero che questo ti aiuti.