2013-05-28 10 views
9

Sono abbastanza nuovo per Scala quindi per favore sii gentile.Test di unità di attori Akka con Scala

Nell'app che sto attualmente costruendo, sto usando gli attori Akka e voglio scrivere alcuni test unitari. Mi sono imbattuto in questo official documentation for writing unit tests for Akka actors

ma non riuscivo a capire esattamente come dovrebbe funzionare. In particolare,

val actorRef = TestActorRef(new MyActor) 
// hypothetical message stimulating a '42' answer 
val future = actorRef ? Say42 
val Success(result: Int) = future.value.get 
result must be(42) 

Quando provo che, ottengo not found: value Success, che non è sorprendente.

Poi ho trovato this example of how to test Scala actors

val actorRef = TestActorRef[TickTock] 

implicit val timeout = Timeout(5 seconds) 
val future = (actorRef ? new Tick("msg")).mapTo[String] 
val result = Await.result(future, timeout.duration) 

Assert.assertEquals("processed the tick message", result) 

, che è certamente forse vecchio, ma è facile da capire e più vicino a quello che io normalmente uso quando voglio usare Futures, e soprattutto funziona. Mi richiede di dichiarare alcuni impliciti come ActorSystem, timeout e così via, che non sembra essere il caso ufficiale ...

Se possibile, mi piacerebbe usare il metodo proposto da la documentazione ufficiale, quindi sarei grato se qualcuno potesse aiutarmi a capire come funziona (in particolare il bit Success) e come usarlo.

+1

avete importazione come '' scala.util._' o scala.util.Success '? – 4lex1v

risposta

12

La risposta alla tua domanda potrebbe essere troppo lunga, perché è impossibile sapere quanto Scala effettivamente conosci. Cercherò di rendere la mia risposta il più breve possibile, ma non esitate per chiedere chiarimenti in qualsiasi momento. Mi scuso inoltre a nome dell'intera community di StackOverflow per farti sentire il bisogno di scusarti a causa di un'apparente mancanza di abilità prima di fare una domanda.

In Scala 2.10 è stato introdotto un concetto di Try. È molto simile a Option. Option è un concetto di gestione di null s. Un valore di tipo Option può assumere due forme: Some(value) o None. Se si dispone di un valore di Option al è possibile eseguire lo schema di corrispondenza su di esso per verificare se si tratta di un valore Some o None e quindi agire di conseguenza. La corrispondenza del pattern si verifica in molti punti di Scala e una di queste è durante l'inizializzazione di val s. Ecco alcuni esempi:

val x = 10 // pattern 'x' on the LHS matches any value on the RHS so 'x' is initialized with 10 
val Some(x) = Some(10) // pattern 'Some(x)' on the LHS matches any value of type 'Some' and binds it's value to x, so 'x' is yet again initialized with 10 

Try è un concetto di gestione delle eccezioni. Un valore di tipo Try può assumere due forme: Success(result) o Failure(throwable). Se hai un valore di tipo Try puoi eseguire lo schema di corrispondenza su di esso per vedere se è un Success o un Failure.

Questo è ciò che accade nel codice (modello corrispondente a Success). A differenza di Option, le due forme di Try non sono incluse nell'ambito di applicazione, il che causa l'errore di compilazione. Questo lo risolverà:

import scala.util.{Try, Success, Failure} 
+0

Grande analogia; Capisco abbastanza bene il Pattern Matching e le Opzioni e sono riuscito a seguire. Non avevo idea di Try, Success and Failure. Suppongo quindi che Future.value.get restituisca un valore di tipo Prova allora? In altre parole, l'esempio nel modo seguente: 'val futureValue = future.value.get futureValue partita { caso di successo (x: Int) => x deve essere (42) caso _ => false deve essere (true) // fallire solo } Quanto sopra funziona per me nei miei test :) – lloydmeta

+1

Sì, esattamente la stessa cosa, ma si dovrebbe definitivamente andare per l'approccio suggerito da Viktor Klang. – agilesteel

+0

Grazie, accetterò la tua risposta perché ha risposto alla mia domanda e chiarito la mia confusione sul successo di più. – lloydmeta

4

In primo luogo non è un buon motivo per usare ottenere il valore dei futures, questo può sollevare un'eccezione se ci fosse un fallimento. Dovresti usare Await.Di conseguenza, come nel tuo esempio secondi, o l'uso pattern matching per lavorare con successo e fallimento:

future match { 
    case Success(value) => // work with value 
    case Failure(ex) => // work with exception 
} 

da usare Success e Failure importazione scala.util._ o scala.util.{Success, Failure}

Here è una documentazione ufficiale per l'ultima versione 2.2- M3.

5

avere il vostro test di estendere la TESTKIT e quindi aggiungere "con ImplicitSender" e quindi è possibile fare cose come:

val yourActor = system.actorOf(Props[MyActor]) 
yourActor ! Say42 
expectMsg(42) 
+0

Grazie, questo mi ha davvero aiutato. Dopo alcune ricerche ho trovato [questo esempio] (http://doc.akka.io/docs/akka/2.1.4/scala/testkit-example.html) che dimostra come usare ImplicitSender con DefaultTimeout, ecc. – lloydmeta