【问题标题】:How to initialize fixture once for all tests in scalatest?如何为scalatest中的所有测试初始化​​一次夹具?
【发布时间】:2015-09-02 08:42:13
【问题描述】:

根据文档,fixture 可以像这样传递给测试:

def withFixture(test: OneArgTest) = {
    val f = veryLengthyInitialization(test.configMap)
    withFixture(test.toNoArgTest(f))
}

describe("Some test") {
   it("should succeed") { f =>
         f.doSomething()
         // ...
    }
    // many other tests
    // ...
 }

问题是每次测试都要进行初始化,而且需要很长时间,所以我希望它只运行一次。文档提出了另一种选择:

  override def beforeAll(configMap: ConfigMap) {
       val fOnce = veryLengthyInitialization(configMap)
       // but how do I pass f to the tests?
       // ugly workaround:
       f = fOnce
 }

 var f: InitType = null

 describe("Some test") {
   it("should succeed") { // hack: no parameter, use var instead
         f.doSomething()
         // ...
    }
    // many other tests
    // ...
 }

它有效,但我的理解是应该避免 null ,并且依赖突变来实现这样基本的东西有点愚蠢。编写此类测试的正确方法是什么?

【问题讨论】:

  • 避免null值的scalaesque方法是使用Option
  • 我不确定 Option 在这种特殊情况下会给我买什么?我的问题是如何重组代码以避免 var。

标签: scala unit-testing scalatest


【解决方案1】:

我不认为对于这个问题有一个在各个方面都很好的解决方案。为了避免var,我有时会做的一件事是按如下方式构建测试:

class SomeTest extends Spec {
  def initFixtures(): SomeFixtureType = ???
  lazy val fixtures = initFixtures()

  describe("Some test") {
    it("should succeed") in {
      fixtures.doSomething()
      // ...
    }
  }
}

这样我就不需要使用beforeAndAfterAll这个东西了,但是如果你想保证在测试之前初始化fixtures,你可以这样做:

override def beforeAll() { 
  super.beforeAll()
  fixtures
}

在处理异步初始化时它也很方便,因为你可以有类似的东西:

class SomeTest extends Spec {
  def initFixtures(): Future[SomeFixtureType] = ???
  lazy val fixtures = initFixtures()

  describe("Some test") {
    it("should succeed") in {
      whenReady(fixtures.flatMap { 
        f.doSomething()
        // ...
      }) { res => doSomeChecks(res) }
    }
  }
}

同时拥有initFixturesfixtures 在这种情况下最有用,因为您可以让一些测试重新初始化系统并在它们需要执行有效操作(例如使用数据库)时单独执行。

【讨论】:

  • 是的,对不起,我没有注意到你的例子中的那一点,我通常不使用ConfigMap,所以我的回答可能与你的情况无关。无论如何,作为beforeAll 的参数提供,如果你想使用它,我不相信有办法避免var:/
【解决方案2】:

我不确定以下是否更好:

trait DoSomething {
  var f:InitType  = _ 
  def doSomething = f.doSomething
}
class MyTestSpec extends DoSomething {
  override def beforeAll(configMap: ConfigMap) {
     val fOnce = veryLengthyInitialization(configMap)
     f = fOnce
  }

  it("should succeed") { 
     doSomething()
   }   
}

对于任何需要 f 变量来做某事的测试,您可以扩展特征并在 beforeAll 方法中对其进行初始化,此外,您甚至可以在测试中覆盖 doSomething。

【讨论】:

  • 也许我错过了一个常见的 Scala 模式,但我不明白在这里添加特征是什么优势。能否详细说明一下好处?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 2021-10-04
  • 2018-02-20
相关资源
最近更新 更多