【问题标题】:Doing something before or after all Scalatest tests在所有 Scalatest 测试之前或之后做某事
【发布时间】:2013-03-03 15:10:27
【问题描述】:

我有一套最大规模的测试来测试 RESTful API 的不同端点。 我真的希望将它们分成不同的文件以便更好地组织。

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

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

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

【问题讨论】:

标签: scala scalatest


【解决方案1】:

这样做的预期方法是使用嵌套套件。 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 忽略它们。

【讨论】:

  • 玩这个有点...尝试未使用的构造函数参数的想法。它从无发现的角度工作,但会引发某种错误: java.lang.IllegalArgumentException: Class is not an access org.scalatest.Suite: com.br.awe.service.test.Api10tests 。在 org.scalatest.tools.ScalaTestFramework$ScalaTestRunner.run(ScalaTestFramework.scala:300) 在 org.scalatools.testing.Runner2.run(Runner2.java:16) 在 sbt.TestRunner.delegateRun(TestFramework.scala:57)。 .. 我的主测试套件是这样开始的:class MasterTestSuite extends Suites(new Api10tests(1), new Api20tests(1))
  • 有没有办法显示内部测试的结果?目前,如果它失败了,它只是认为 EndpointTests 失败了。很高兴看到套件内部哪些测试失败了。
  • ScalaTest scalatest.org/release_notes/2.0
  • 在 scalatest 2.2.5 中,您不需要将配置传递给 beforeAll 方法:` @deprecated("请改用 trait BeforeAndAfterAllConfigMap 的 beforeAll(ConfigMap) 方法。") protected def beforeAll(configMap : ConfigMap) { beforeAll() } `
  • 请注意,使用这种方法我们会失去运行单个套件的能力。
【解决方案2】:

好的,找到方法了。看来(除非这里有人可以纠正我)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
        }   
}

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

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!") {  }
    }
}

【讨论】:

  • Bill 的上述答案因测试失败细节被吞下而受苦——如果您真的想知道出了什么问题,这是没有用的。不幸的是,这种方法的副作用是BeforeAndAfterAll 即使在单个测试中也适用于整个套件。此外,您不再可以单独运行测试,并且它们的输出全部写入控制台。我真的希望 ScalaTest 有比这更好的答案。
【解决方案3】:

您也可以只使用一个对象。

object TestServer {
  startServer()
}

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

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

【讨论】:

  • 我可以看到这在很多情况下对我来说比“BeforeAndAfterAll”更好。例如现在我正在使用 etcd 后端进行测试,并且使用 Object 可以让我运行相同的实例,以进行多个测试。
  • object TestServer { startServer();覆盖 def finalize(): Unit = { super.finalize(); stopServer() }}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-30
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 2014-03-27
  • 2019-07-19
相关资源
最近更新 更多