2013-11-26 15 views
7

Podążam za przykładami testowania Scali, używając specyfikacji Specs2 z oficjalnej dokumentacji Play. Zauważyłem, że używają oni WithApplication założyć fałszywy wniosek do przetestowania przeciw, z Clode jak następuje:Zagraj w Famework 2 - Scala - Rozpocznij jedną aplikację dla zestawu testowego

"something" should { 
    "do X" in new WithApplication { /* ... */ } 
    "do Y" in new WithApplication { /* ... */ } 
    "do Z" in new WithApplication { /* ... */ } 
} 

To jest w porządku i wszystko, ale jest problem, że mam to, że ponoszą koszty moja aplikacja uruchamia się za każdym razem, gdy tak się dzieje. To niekoniecznie jest "szybkie" lub przynajmniej niewystarczająco szybkie, gdy zestaw testowy powiększy się do rozsądnego rozmiaru. Próbowałem robić takie rzeczy jak:

val app = FakeApplication() 
"something" should { 
    "do X" in new WithApplication(app) { /* ... */ } 
    "do Y" in new WithApplication(app) { /* ... */ } 
    "do Z" in new WithApplication(app) { /* ... */ } 
} 

i

"something" should { 
    val app = FakeApplication() 
    Helpers.running(app) { 
     "do X" in { /* ... */ } 
     "do Y" in { /* ... */ } 
     "do Z" in { /* ... */ } 
    } 
} 

Pierwszy wydaje się działać dla pierwszego badania, a potem narzeka na problemy z połączeniem db na późniejszych testów. Zgaduję, że coś tu się kończy albo coś (nie wiem co).

Drugi nie działa, ponieważ narzeka, że ​​nie ma uruchomionej aplikacji, co do której nie jestem pewien.

Każda pomoc jest bardzo doceniana. Dzięki!

Odpowiedz

4

Cóż, to zależy od tego, co chcesz przetestować. Jeśli jesteś tylko jednostkowym testowaniem kodu, który nie ma żadnych zewnętrznych zależności lub zależności, które możesz udawać lub wyrzucać (i dobrze byłoby ustrukturyzować twój kod w taki sposób, który na to pozwala), to nie musisz użyj WithApplication. To chyba najlepsze podejście.

Pierwsze podane rozwiązanie nie działa, ponieważ aplikacje mogą być używane tylko raz. Jest to WithApplication, które uruchamia i zatrzymuje Twoją aplikację, więc nawet gdyby to zadziałało, nie uzyskałbyś żadnych korzyści z wydajności.

Drugie podane rozwiązanie nie działa, ponieważ po uruchomieniu bloku kodu Helpers.running(app) { } deklarowana jest tylko specyfikacja. Specyfikacja umieszcza je wszystkie na liście, a następnie wychodzi z uruchomionego bloku i zamyka aplikację. Następnie, w pewnym momencie, specyfikacja uruchamia testy, a wtedy nie ma zastosowania.

Jeśli więc nie możesz przetestować swojego kodu w oderwaniu od reszty aplikacji, musisz mieć działającą aplikację, nic nie możesz na to poradzić, to rzeczywistość testów integracyjnych. Prawdopodobnie chcesz, aby to się zaczęło i wyłączało między testami, w przeciwnym razie twoje testy nie będą działać w izolacji od siebie.

3

Jest przestarzały, ale dam odpowiedź. Odkąd stanąłem przed tym samym problemem i miałem podobny pomysł. Jest przecież & BeforeAll cechy w spec2, może to nie było w czasie postu, więc moje rozwiązanie jest w zasadzie:

package com.equipx.spec.util 

import org.specs2.specification.{AfterAll, BeforeAll} 
import play.Application 
import play.api.Play 
import play.test.{Helpers, FakeApplication} 

/** 
* @author Anton Oparin ([email protected]) 
*/ 
trait WithGlobalApplication extends BeforeAll with AfterAll { 

    protected var app: Application = null 

    /** 
    * Override this method to setup the application to use. 
    * 
    * By default this will call the old {@link #provideFakeApplication() provideFakeApplication} method. 
    * 
    * @return The application to use 
    */ 
    protected def provideApplication: Application = { 
    return provideFakeApplication 
    } 

    /** 
    * Old method - use the new {@link #provideApplication() provideApplication} method instead. 
    * 
    * Override this method to setup the fake application to use. 
    * 
    * @return The fake application to use 
    */ 
    protected def provideFakeApplication: FakeApplication = { 
    return Helpers.fakeApplication 
    } 

    override def beforeAll { 
    app = provideApplication 
    Helpers.start(app) 
    Play.current 
    } 

    override def afterAll { 
    if (app != null) { 
     Helpers.stop(app) 
     app = null 
    } 
    } 

} 

Zasadniczo Wziąłem realizację WithApplication i uczynił to globalny.