2013-03-15 16 views
55

Ho una suite di test più scalari che testano diversi endpoint di un'API RESTful. Li voglio davvero separati in file diversi per la migliore organizzazione.Esegui qualcosa prima o dopo tutti i test Scalatest

Il mio problema è come avviare qualcosa (un server HTTP nel mio caso, ma non importa di cosa si tratta) prima di tutti i test e spegnerlo dopo aver eseguito tutti i test.

Sono a conoscenza di BeforeAndAfterAll, ma ciò avviene solo prima/dopo all'interno di un file di test. Ho bisogno di qualcosa di simile, ma per tutte le prove, ad esempio:

- avvio del server HTTP prima test
- eseguire tutte le suite di test
- Arrestare http server di

+0

Vedere questa domanda/risposta (non proprio un duplicato) -> http: // stackoverflow.it/questions/8486869/org-scalatest-global-setup-like-beforeallsuites –

+0

Controlla questo q/a: http://stackoverflow.com/questions/27272811/how-to-cut-a-long-scalatest-spec- to-pieces/27275814 Volevo mantenere il passo di inizializzazione come test stesso, con test dipendenti assicurandoti che l'inizializzazione fosse eseguita per prima, e cancellando se avesse fallito – akauppi

risposta

40

Il modo previsto per farlo è quello di utilizzare suite nidificate. Suite ha un metodo nestedSuites che restituisce IndexedSeq [Suite] (in 2.0, in 1.9.1 era una List [Suite]). Suite ha anche un metodo runNestedSuites che è responsabile dell'esecuzione di eventuali suite nidificate. Per impostazione predefinita runNestedSuites chiama nestedSuites e su ogni Suite restituita invoca direttamente o, se viene passato un Distributore, mette le suite nidificate nel distributore in modo che possano essere eseguite in parallelo.

Quindi ciò che si vuole veramente fare è rendere Foo e Bar in classi, e restituire loro istanze dal metodo nestedSuites di EndpointTests. C'è una classe che rende facile quella Suite. Ecco un esempio di utilizzo:

import org.scalatest._ 
import matchers.MustMatchers 

class Foo extends FunSpec with MustMatchers { 
    describe("Message here...") { 
    it("Must do something") { } 
    it("Must be ok") { } 
    } 
} 

class Bar extends FunSpec with MustMatchers { 
    describe("Hello you...") { 
    it("One more!") { } 
    } 
} 

class EndpointTests extends Suites(new Foo, new Bar) with BeforeAndAfterAll { 

    override def beforeAll(configMap: Map[String, Any]) { 
    println("Before!") // start up your web server or whatever 
    }  

    override def afterAll(configMap: Map[String, Any]) { 
    println("After!") // shut down the web server 
    }   
} 

Un potenziale problema, però, è che se si sta utilizzando la scoperta di trovare Suites per eseguire, tutti e tre EndpointTests, Foo e bar sarà scoperto. In ScalaTest 2.0 puoi annotare Foo e Bar con @DoNotDiscover e il Runner di ScalaTest non li scoprirà. Ma sbt lo farà ancora. Attualmente stiamo migliorando sbt in modo che passi su Suites altrimenti individuabili annotati con DoNotDiscover, ma questo sarà in 0.13 sbt, che non è ancora uscito. Nel frattempo puoi far sì che sbt li ignori aggiungendo un parametro costruttore inutilizzato a Foo e Bar.

+0

Giocando con questo un po '... Provando l'idea del parametro costruttore inutilizzato. Funziona da un punto di non-scoperta ma genera qualche tipo di errore: java.lang.IllegalArgumentException: Class non è un oggetto accessibile org.scalatest.Suite: com.br.awe.service.test.Api10tests. \t a org.scalatest.tools.ScalaTestFramework $ ScalaTestRunner.run (ScalaTestFramework.scala: 300) \t a org.scalatools.testing.Runner2.run (Runner2.java:16) \t a sbt.TestRunner.delegateRun (TestFramework .scala: 57) ... La mia suite di test principale inizia così: classe MasterTestSuite estende Suites (nuovo Api10tests (1), nuovo Api20tests (1)) – Greg

+1

C'è un modo per mostrare i risultati per i test interni? Al momento, se fallisce, si limita a sostenere che gli EndpointTests falliscono. Sarebbe bello vedere quali test hanno fallito all'interno della suite. – Nacht

+0

C'è un bug che causa un deadlock per questo approccio in ScalaTest <2.0.M8, quindi assicurati di aggiornare. Vedi le note di rilascio per M8 qui: http://www.scalatest.org/release_notes/2.0 –

5

Ok, ha trovato un modo . Sembra (a meno che qualcuno qui non possa correggermi) che Scalatest non abbia la funzione di una suite "master". Ma ... puoi costruirne uno.

È possibile comporre una suite dai tratti. Quindi, usando il mio esempio di endpoint:

class EndpointTests extends FunSpec with MustMatchers with BeforeAndAfterAll 
     with Foo with Bar { 
     override def beforeAll(configMap: Map[String, Any]) { 
      println("Before!") // start up your web server or whatever 
     } 

     override def afterAll(configMap: Map[String, Any]) { 
      println("After!") // shut down the web server 
     } 
} 

Ok, ma per quanto riguarda i test? Notare il con Foo con Bar. Sto portando i test dipendenti come tratti. Vedi qui:

trait Foo extends FunSpec with MustMatchers { 
    describe("Message here...") { 
     it("Must do something") { } 
     it("Must be ok") { } 
    } 
} 

trait Bar extends FunSpec with MustMatchers { 
    describe("Hello you...") { 
     it("One more!") { } 
    } 
} 
6

In alternativa puoi semplicemente usare un oggetto.

object TestServer { 
    startServer() 
} 

Quando si accede l'oggetto verrà inizializzato, l'avvio del server. Basta creare un tratto comune nel corpo di cui si accede all'oggetto. Quindi configura quel tratto in tutti i tuoi test. Fatto.

Se il server viene eseguito in modalità daemon (ad esempio un'applicazione Play! In modalità test), verrà automaticamente arrestato dopo l'esecuzione di tutti i test.

+0

Posso vederlo funzionare in molti casi meglio per me di "BeforeAndAfterAll". per esempio. ora sto testando con un back-end di etcd, e l'utilizzo di un Object mi permette di avere la stessa istanza in esecuzione, per test multipli. – akauppi

Problemi correlati