我有一个非常具体的用例,为了减少测试套件的实例化时间,我将它们定义为对象而不是类。
import org.scalatest._
import scala.collection.mutable.Stack
object StackSuite extends FunSuite with Matchers {
test("stackShouldPopValuesIinLastInFirstOutOrder") {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
stack.pop() should equal(2)
stack.pop() should equal(1)
}
}
这是可行的,但这样做是否存在根本问题或缺陷?如果每个测试都单独执行,并且在套件级别具有可修改状态的不幸情况下,则与多线程问题分开。
更新:当我说“减少实例化时间”时,我指的是整体,例如考虑对象/类中的重量级夹具数据,而不仅仅是纯套件类实例化时间。由于对象是单例,因此它将是查找而不是新类的实例化。
我需要这样做,以便在计算机网格中分发数百万个测试。一些测试是标准的标量测试,其他测试是评估一组输入参数的排列,因此需要减少套件实例化的启动时间。
顺便说一下,我这样做是为了在集群机器中执行每个测试:
import scala.reflect.runtime.universe
// I receive the suite and test names as input
val suite = "com.mycomp.StackSuite"
val test = "stackShouldPopValuesIinLastInFirstOutOrder"
val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
val module = runtimeMirror.staticModule(suite)
val obj = runtimeMirror.reflectModule(module)
val status = obj.asInstanceOf[TestSuite].execute(test)
为了减少测试套件的实例化时间,我将它们定义为对象而不是类
我快速查看了org.scalatest.tools.Runner
(和DiscoverySuite
)实现,我认为这不会减少实例化时间。
记住对象
实际上是如何在JVM上编译的:你有一个类StackSuite$
,它扩展了Suite,并有一个公共的无参数构造函数(因为它必须从StackSuite
的静态初始值设定项调用)。它的发现和处理就像
一个类StackSuite
一样。
编辑:如果你找到这个套件并自己用这种方式运行它,而不是使用ScalaTest自己的API,那么是的,你会得到一个查找而不是实例化。假设没有并发问题,应该没有问题:< code>execute本身就是线程安全的。
如果你觉得没有必要通过使用继承来模块化你的测试,那么使用一个对象而不是一个类是没有问题的。Else类可以帮助你分离不同种类的测试。
从ScalaTest文档中:
我们建议您为您的项目创建抽象基类,将您最常用的功能混合在一起,而不是通过重复混合相同的特征来复制代码。例如,您可以为单元测试创建一个UnitSpec类(不是trait,用于更快的编译),如下所示:
package com.mycompany.myproject
import org.scalatest._
abstract class UnitSpec extends FlatSpec with Matchers with
OptionValues with Inside with Inspectors
然后可以使用自定义基类为项目编写单元测试,如下所示:
package com.mycompany.myproject
import org.scalatest._
class MySpec extends UnitSpec {
// Your tests here
}