12.9 用JUnit运行ScalaTest
至此,想必你已然爱上了ScalaTest,但很快就又会意识到,项目里面绝大多数测试都是用JUnit或TestNG写的。你很困惑,能不能既用上ScalaTest那简洁的语法和众多特性,还可以用JUnit或TestNG运行测试呢?JUnit3Suite
和TestNGSuite
就可以做到这一点。你只需要让测试套件继承JUnit3Suite
,JUnit就可以识别出来了,测试方法自然还是按照你的爱好去写:你可以用ScalaTest的assert()
、expect()
和intercept()
,还有上面提到的用函数式风格共享代码。这样写成的测试,不管是ScalaTest还是JUnit都可以运行。不过它只支持JUnit 3.x(在JUnit 3.8.1上测试过),不支持JUnit 4.0⑪。下面是JUnit3Suite
的使用示例:
⑪ScalaTest 1.0 支持JUnitSuite,用于JUnit 4.x。——译者注
UnitTestingWithScala/UsingJUnit3Suite.scala
class UsingJUnit3Suite extends org.scalatest.junit.JUnit3Suite {
def withList(testFunction : (java.util.ArrayList[Integer]) => Unit) {
val list = new java.util.ArrayList[Integer]
try {
testFunction(list)
}
finally {
// perform any necessary cleanup here after return
}
}
def testListEmptyOnCreate() {
withList { list => expect(0, "Expected size to be 0") { list.size() } }
}
def testGetOnEmptyList() {
withList {
list => intercept[IndexOutOfBoundsException] { list.get(0) }
}
}
}
下面是用JUnit运行上述测试的Scala代码:
UnitTestingWithScala/RunJUnitTest.scala
object RunJUnitTest {
def main(args: Array[String]) =
junit.textui.TestRunner.run(classOf[UsingJUnit3Suite])
}
上段代码编译后,用ScalaTest和JUnit都能运行。
接下来你可以看到怎么进行编译,然后分别用两种工具运行:
scalac -classpath $SCALATEST:$JUNITJAR:. \
UsingJUnit3Suite.scala RunJUnitTest.scala
echo "Running ScalaTest"
scala -classpath $SCALATEST:$JUNITJAR:. \
org.scalatest.tools.Runner -o -p . -s UsingJUnit3Suite
echo "Running JUNIT test"
java -classpath $SCALALIBRARY:$SCALATEST:$JUNITJAR:. RunJUnitTest
测试代码的输出如下:
Running ScalaTest
Run starting. Expected test count is: 2
Suite Starting - UsingJUnit3Suite: The execute method of a nested suite
is about to be invoked.
Suite Starting - UsingJUnit3Suite: UsingJUnit3Suite
Test Starting - testGetOnEmptyList: UsingJUnit3Suite
Test Succeeded - testGetOnEmptyList: UsingJUnit3Suite
Test Starting - testListEmptyOnCreate: UsingJUnit3Suite
Test Succeeded - testListEmptyOnCreate: UsingJUnit3Suite
Suite Completed - UsingJUnit3Suite: UsingJUnit3Suite
Suite Completed - UsingJUnit3Suite: The execute method of a nested
suite returned normally.
Run completed. Total number of tests run was: 2
All tests passed.
Running JUNIT test
..
Time: 0.02
OK (2 tests)
在上面的例子中,你看到了怎么用Scala和JUnit来运行ScalaTest写的测试。这个特性降低了把Scala引入当前项目编写单元测试的门槛。现在就用不着在JUnit(或TestNG)和ScalaTest之间二选一了。二者可以相得益彰,既用上Scala的简洁,又保留着项目中现有的完好框架。
编写单元测试时,人们常常要依赖mock对象来打桩,或是模拟被测代码所依赖的代码。如果你用过EasyMock或是JMock之类的框架创建mock对象,也同样可以在Scala里使用它们。使用这些Mock框架时,可以充分利用Scala的诸多特性,如trait、函数式风格和简洁。
在这章里,你已经学到了很重要的工具和实践。不过,你或许也该明白,单元测试并不仅仅是这些工具而已,它还需要个人的修炼和努力。我衷心希望Scala在测试上表现出来的优雅和ScalaTest所提供的便利,能够激励你开始编写测试,或是把测试继续写好。在下一章里,我们共同探索Scala的异常处理与Java的异同。