74

我有一套 scalatest 测试来测试 RESTful API 的不同端点。我真的希望将它们分成不同的文件以实现最佳组织。

我的问题是如何在所有测试之前启动某些东西(在我的情况下是一个 HTTP 服务器,但它是什么并不重要)并在所有测试完成后关闭它。

我知道 BeforeAndAfterAll,但这只能在一个测试文件中完成之前/之后。我需要类似的东西,但对于所有测试,例如:

-- 测试前启动 http 服务器
-- 运行所有测试套件
-- 关闭 http 服务器

4

3 回答 3

57

这样做的预期方法是使用嵌套套件。Suite 有一个 nestedSuites 方法,它返回一个 IndexedSeq[Suite](在 2.0 中,在 1.9.1 中它是一个 List[Suite])。Suite 还有一个 runNestedSuites 方法,负责执行任何嵌套的套件。默认情况下,runNestedSuites 调用nestedSuites,并且在每个返回的套件上直接调用 run,或者如果传递了 Distributor,则将嵌套套件放入分发器中,以便它们可以并行运行。

因此,您可能真正想做的是将 Foo 和 Bar 放入类,并从 EndpointTests 的nestedSuites 方法返回它们的实例。有一个类叫做 Suites。这是它的使用示例:

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
  }         
}

但是,一个潜在的问题是,如果您使用发现来查找要运行的套件,则会发现所有三个 EndpointTest、Foo 和 Bar。在 ScalaTest 2.0 中,您可以使用 @DoNotDiscover 注释 Foo 和 Bar,ScalaTest 的 Runner 不会发现它们。但 sbt 仍然会。我们目前正在增强 sbt,以便它通过其他可发现的带有 DoNotDiscover 注释的套件,但这将在 sbt 0.13 中,尚未发布。同时,您可以通过向 Foo 和 Bar 添加未使用的构造函数参数来让 sbt 忽略它们。

于 2013-03-21T19:27:19.807 回答
12

好的,找到方法了。Scalatest 似乎没有“主”套件的功能(除非这里有人可以纠正我)。但是......你可以建造一个。

您可以从特征组成一个套件。所以使用我的端点示例:

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
        }   
}

好的,但是测试呢?注意 with Foowith Bar。我将依赖测试作为特征引入。看这里:

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!") {  }
    }
}
于 2013-03-15T02:31:11.670 回答
11

或者,您可以只使用一个对象。

object TestServer {
  startServer()
}

当您访问对象时,它将被初始化,启动服务器。只需在您访问对象的主体中创建一个公共特征。然后将该特征混入您的所有测试中。完毕。

如果您的服务器以守护程序模式运行(例如处于测试模式的 Play! 应用程序),它将在所有测试运行后自动关闭。

于 2014-06-01T16:31:26.440 回答