2012-09-03 2 views
9

Ho un test specs2 che utilizza FakeApplication e un database integrato di mongodb.Play 2.0 Installazione di FakeApplication con configurazione di test

def inMemoryMongoDatabase(name: String = "default"): Map[String, String] = { 
    val dbname: String = "play-test-" + scala.util.Random.nextInt 
    Map(
     ("mongodb." + name + ".db" -> dbname), 
     ("mongodb." + name + ".port" -> EmbeddedMongoTestPort.toString)) 
} 

override def around[T <% Result](t: => T) = { 
    running(FakeApplication(additionalConfiguration = inMemoryMongoDatabase(), additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"))) { 
     t // execute t inside a http session 
    } 
} 

Il FakeApplication utilizza la configurazione predefinita application.conf nella directory conf e la configurazione aggiuntiva per i database di test che vengono creati per ogni test.
Questo funzionava trovare fino a quando non abbiamo impostato un set di repliche mongodb. Ora l'application.conf contiene la configurazione per questo Replicat set

mongodb.default.replicaset { 
host1.host = "localhost" 
host1.port = 27017 
host2.host = "localhost" 
host2.port = 27018 
host3.host = "localhost" 
host3.port = 27019 
} 

Come il FakeApplication utilizza la configurazione predefinita i test falliscono perché i padroni di casa del replicaset non può essere trovato. Voglio avere una configurazione diversa per i miei test, in pratica rimuovo la voce mongodb.default.replicaset. Se mongodb.default.replicaset fosse una semplice Map [String, String] sarebbe facile dato che potrei semplicemente aggiungerla ad additonalConfiguration ma quando provo a farlo fallisce perché il tipo di valore atteso non è una String ma un Object. Ho anche provato a fornire un file test.conf separato a FakeApplication tramite il parametro path.

override def around[T <% Result](t: => T) = { 
    running(FakeApplication(path = new java.io.File("conf/test.conf"), additionalConfiguration = inMemoryMongoDatabase(), additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"))) { 
     t // execute t inside a http session 
    } 
} 

Che non ha funzionato in quanto non ha caricato alcuna configurazione.

Apprezzerei molto qualsiasi aiuto. Grazie.

Chris

risposta

3

Il problema è come specificare il file test.conf quando si esegue un test di integrazione utilizzando Play's FakeAppication. Nel mio test di integrazione non posso chiamare play -Dconfig.file=conf/test.conf.

cosa sono riuscito a fare è questo:

object FakeSalatApp extends Around { 

def EmbeddedMongoTestPort: Int = 27028 

def inMemoryMongoDatabase(name: String = "default"): Map[String, String] = { 
    val dbname: String = "play-test-" + scala.util.Random.nextInt 
    Map(
    ("mongodb." + name + ".db" -> dbname), 
    ("mongodb." + name + ".port" -> EmbeddedMongoTestPort.toString), 
    ("mongodb." + name + ".replicaset.host1.host" -> "localhost"), 
    ("mongodb." + name + ".replicaset.host1.port" -> EmbeddedMongoTestPort.toString), 
    ("mongodb." + name + ".replicaset.host2.host" -> "localhost"), 
    ("mongodb." + name + ".replicaset.host2.port" -> (EmbeddedMongoTestPort + 1).toString), 
    ("mongodb." + name + ".replicaset.host3.host" -> "localhost"), 
    ("mongodb." + name + ".replicaset.host3.port" -> (EmbeddedMongoTestPort + 2).toString)) 
    } 

override def around[T <% Result](t: => T) = { 
    running(FakeApplication(additionalConfiguration = inMemoryMongoDatabase(), additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"))) { 
    t // execute t inside a http session 
    } 
} 
} 
0

Utilizzando path non funziona qui, dal momento che questo è il percorso del FakeApplication si sta eseguendo (si potrebbe avere un percorso diverso in alcuni casi).

Quello che suggerirei nel vostro caso è specificare un test.conf quando si esegue la modalità di riproduzione per test, come ad es.

play -Dconfig.file=conf/test.conf 

Quindi test.conf verrà prelevato. Potresti anche includere il normale application.conf e sovrascrivere solo le impostazioni di mongo.

Forse avrebbe anche senso avere la "modalità obiettivo singolo" come modo predefinito di connettersi a mongodb nel proprio application.conf e sovrascrivere la configurazione mongob per utilizzare un replicaset solo in una configurazione di produzione.

10

Abbiamo avuto un problema simile caricamento configurazioni in più per i nostri test di integrazione. Abbiamo trovato che popolano le mappe manualmente per essere noioso così abbiamo usato il seguente approccio:

private Configuration additionalConfigurations; 
@Before 
public void initialize(){ 
    Config additionalConfig = ConfigFactory.parseFile(new File("conf/integration.conf")); 
    additionalConfigurations = new Configuration(additionalConfig); 
} 
@Test 
public void testPropertiesGetLoaded() throws Exception{ 
    running(testServer(3333, fakeApplication(additionalConfigurations.asMap())), HTMLUNIT, new Callback<TestBrowser>(){ 
     public void invoke(TestBrowser browser){ 
      String specificProperty = Play.application().configuration().getString("specific.property"); 
      System.out.println(specificProperty); 
     } 
    }); 
} 

Non so se c'è un bel metodo sul lato Scala di cose, stiamo facendo tutto il nostro codice in Java.

2

Ecco come l'ho fatto in Play 2.3.x

  1. Definire la mia domanda GlobalSettings in una classe AppGlobal in un pacchetto (non il package principale)

    package configs 
    
    class AppGlobal extends GlobalSettings { 
        // Your application global settings 
        ??? 
    } 
    
  2. Definire le impostazioni globali dell'applicazione come object Global extends AppGlobal che viene utilizzato l'applicazione.

  3. Nella classe di test, definire un test globale. La configurazione di prova viene aggiunto alla fine di ignorare o aggiungere alla configurazione dell'applicazione complessiva:

    object TestGlobal extends AppGlobal { 
        override def onLoadConfig(config: Configuration, 
              path: File, 
              classloader: ClassLoader, 
              mode: Mode): Configuration = { 
        config ++ configuration ++ 
          Configuration.load(path, mode = Mode.Dev, 
              Map("config.file" -> "conf/test.conf")) 
        } 
    } 
    
  4. creare l'applicazione falso con quanto sopra TestGlobal

    FakeApplication(withGlobal = Some(TestGlobal)) 
    
1

Nel mio caso ho semplicemente creato una classe base che estende tutti i miei test. Subito prima di creare l'applicazione Fake definisco la proprietà di sistema config.resource che imposta la configurazione dell'applicazione. Poi sono strutturate le configurazioni come segue:

application.conf: contiene-env configurazioni specifiche

test.conf: include application.conf e definisce configurazioni per eseguire il test dell'unità

env_local. conf: include application.conf e definisce le configurazioni per eseguire l'applicazione a livello locale

env_prod.conf: come env_local.conf ma per la produzione ecc ...

Nel mio progetto, per comodità ho ingabbiati un local.sh sceneggiatura che semplicemente funziona attivatore -Dconfig.resource = env_local.conf

@RunWith(classOf[JUnitRunner]) 
class ApplicationTest extends FunSuite with MockitoSugar { 
    System.setProperty("config.resource", "test.conf") 
    val app = Helpers.fakeApplication() 
}