在所有 Scalatest 测试之前或之后做某事
Posted
技术标签:
【中文标题】在所有 Scalatest 测试之前或之后做某事【英文标题】:Doing something before or after all Scalatest tests 【发布时间】:2013-03-03 15:10:27 【问题描述】:我有一套最大规模的测试来测试 RESTful API 的不同端点。 我真的希望将它们分成不同的文件以便更好地组织。
我的问题是如何在所有测试之前启动某些东西(在我的例子中是一个 HTTP 服务器,但它是什么并不重要)并在所有测试完成后关闭它。
我知道 BeforeAndAfterAll,但这仅在一个测试文件中完成之前/之后。我需要类似的东西,但对于所有测试,例如:
-- 测试前启动http服务器 -- 运行所有测试套件 -- 关闭http服务器
【问题讨论】:
查看这个问题/答案(不完全重复)-> ***.com/questions/8486869/… 检查这个 q/a:***.com/questions/27272811/… 我想将初始化步骤保留为测试本身,依赖测试确保首先运行初始化,如果失败则取消 【参考方案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
好的,但是测试呢?注意Foo
和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!")
【讨论】:
Bill 的上述答案因测试失败细节被吞下而受苦——如果您真的想知道出了什么问题,这是没有用的。不幸的是,这种方法的副作用是BeforeAndAfterAll
即使在单个测试中也适用于整个套件。此外,您不再可以单独运行测试,并且它们的输出全部写入控制台。我真的希望 ScalaTest 有比这更好的答案。【参考方案3】:
您也可以只使用一个对象。
object TestServer
startServer()
当您访问对象时,它将被初始化,启动服务器。 只需在您访问对象的主体中创建一个公共特征。 然后将该特征混入您的所有测试中。完成。
如果您的服务器以守护程序模式运行(例如,处于测试模式的 Play! 应用程序),它将在所有测试运行后自动关闭。
【讨论】:
我可以看到这在很多情况下对我来说比“BeforeAndAfterAll”更好。例如现在我正在使用 etcd 后端进行测试,并且使用 Object 可以让我运行相同的实例,以进行多个测试。 object TestServer startServer();覆盖 def finalize(): Unit = super.finalize(); stopServer()以上是关于在所有 Scalatest 测试之前或之后做某事的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ScalaTest / SBT 中按顺序运行测试套件?