【问题标题】:Fast test execution in a playframework fake application在 playframework 假应用程序中快速执行测试
【发布时间】:2013-12-13 19:36:43
【问题描述】:

按照here 的描述运行测试

"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()}
}

}

优点:性能提升

缺点:

  • 需要复制粘贴设置和拆卸代码,因为不知道如何 重用它(通过重用我的意思是“class MySpec extends 使用 NoWasteOfTime"

  • 的规范
  • new WithApplication() 调用 Helpers.running,如下所示

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

所以我无法完全模拟 Helpers.running 行为(resetClient 对我的代码不可见)而无需反射。

请建议如何打破缺点或不同的方法来解决我的问题。

【问题讨论】:

  • 你想为一个规范设置/拆卸一次,还是你想为其中的每个测试都做一次?
  • 太糟糕了,18 个月过去了,Play 仍然没有改变这种行为。为每个测试启动应用程序是可笑的。 Play 3 将具有 DI,有望完全消除对运行应用程序的需求。

标签: scala playframework playframework-2.2 specs2


【解决方案1】:

我不知道这是否是最好的解决方案,但在这个线程中: 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()
}

我认为mapStep(...) ^ fragments ^ Step(...) 一起使用会更好,但它并没有为我运行 beforeAll。 “全局设置/拆卸”中的用户指南 (http://bit.ly/11I9kFM) 说要使用惰性验证。

总的来说,设置它很痛苦。我的问题是 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.

我认为这种方式比总是为每个“in”块创建一个新应用程序或将所有测试添加到一个块中更合乎逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 2011-11-01
    • 1970-01-01
    相关资源
    最近更新 更多