2013-11-27 23 views
8

運行測試所描述的here快速測試執行的playframework假的應用

"Spec" should { 
    "example" in new WithApplication { 
    ... 
    } 
} 

對我來說是不可接受的慢。這是因爲新的WithApplication在每個示例都啓動和停止框架。不要誤解我的意思,框架本身的加載速度非常快,但是如果配置了數據庫(意外!),情況會變得很糟糕。

下面是一些觀測值:

"The database layer" should { 

    "test1" in { 
    1 must be equalTo(1) 
    } 
    ... 
    "test20" in { 
    1 must be equalTo(1) 
    } 
} 

執行時間:2秒。同樣的測試與WithApplication在每一個例子消耗9秒

我能夠更好的結果得益於才達到到this answer

import play.api.Play 
import play.api.test.FakeApplication 
import org.specs2.mutable.Specification 
import scalikejdbc._ 

class MySpec extends Specification { 

var fake: FakeApplication = _ 

step {fake = FakeApplication(...)} 
step {Play.start(fake)} 

"The database layer" should { 

    "some db test" in { 
    DB localTx { implicit session => 
     ... 
    } 
    } 

    "another db test" in { 
    DB localTx { implicit session => 
     ... 
    } 
    } 

    step {Play.stop()} 
} 

}

優點:性能提升

缺點:

  • 需要複製粘貼安裝和拆除的代碼,因爲不知道如何 重用(通過重用我的意思是像「類MySpec擴展 規格與NoWasteOfTime

  • 新WithApplication()來電Helpers.running它看起來像這樣

synchronized { 
    try { 
    Play.start(fakeApp) 
    block 
    } finally { 
    Play.stop() 
    play.api.libs.ws.WS.resetClient() 
    } 
} 

,所以我不能完全效仿Helpers.running行爲(resetClient對我的代碼不可見),沒有反射。

請建議如何打破缺點或不同的方法如何完成我的問題。

+0

您是否想爲規範設置/拆卸一次,還是想爲其中的每個測試執行一次? –

+0

18個月後它太糟糕了,Play仍然沒有改變這種行爲。爲每個測試啓動應用程序是可笑的。 Play 3將會有DI,希望完全消除對運行應用程序的需求。 – andyczerwonka

回答

9

我不知道這是否是最佳的解決方案,但在這個線程: Execute code before and after specification

您可以閱讀可重用代碼的解決方案。我稍作修改就實現了它。對於我來說,beforeAll步驟沒有運行,並添加了sequential修飾符。

import org.specs2.mutable._ 
import org.specs2.specification._ 

class PlayAppSpec extends Specification with BeforeAllAfterAll{ 
    sequential 
    lazy val app : FakeApplication = { 
     FakeApplication() 
    } 

    def beforeAll(){ 
     Play.start(app) 
    } 

    def afterAll(){ 
     Play.stop() 
    } 
} 
import org.specs2.specification.Step 

trait BeforeAllAfterAll extends Specification { 
    // see http://bit.ly/11I9kFM (specs2 User Guide) 
    override def map(fragments: =>Fragments) = { 
    beforeAll() 
    fragments^Step(afterAll) 
    } 


    def beforeAll() 
    def afterAll() 
} 

我覺得map將與更好Step(...)^fragments^Step(...),但它並沒有爲我運行beforeAll。 「Global setup/teardown」中的用戶指南(http://bit.ly/11I9kFM)表示使用惰性val。

總的來說,這是一個痛苦。我的問題是 Exception in thread "Thread-145" java.net.SocketException: Connection reset 或者

Configuration error[Cannot connect to database [default]] (Configuration.scala:559)

當重複使用相同的FakeApplication: SQLException: Attempting to obtain a connection from a pool that has already been shutdown.

我覺得這是更合乎邏輯相比,這樣總是「在」塊創建爲每個新的應用程序或將所有測試添加到一個塊中。

+0

我絕對喜歡你的方法,就像魅力一樣。 – Jeriho