01.02.JUnit 4 と ScalaTest の始め方

もし、JUnit 4 のテストを Scala で記述し実行したいなら、ScalaTest の アサーションとマッチャーを使って、もっと簡潔なコードを書くことができるでしょう。

アサーションを使うには、org.scalatest.junit.AssertionsForJUnit をミックスインします。

import org.scalatest.junit.AssertionsForJUnit import scala.collection.mutable.ListBuffer import org.junit.Assert._ import org.junit.Test import org.junit.Before class ExampleSuite extends AssertionsForJUnit { var sb: StringBuilder = _ var lb: ListBuffer[String] = _ @Before def initialize() { sb = new StringBuilder("ScalaTest は") lb = new ListBuffer[String] } @Test def verifyEasy() { // JUnit スタイルのアサーションを使用 sb.append("かんたん!") assertEquals("ScalaTest はかんたん!", sb.toString) assertTrue(lb.isEmpty) lb += "sweet" try { "verbose".charAt(-1) fail() } catch { case e: StringIndexOutOfBoundsException => // こうなるはず } } @Test def verifyFun() { // ScalaTest アサーションを使用 sb.append("たのしい!") assert(sb.toString === "ScalaTest はたのしい!") assert(lb.isEmpty) lb += "sweeter" intercept[StringIndexOutOfBoundsException] { "concise".charAt(-1) } } }

注意:

JUnit は伝統的に、アサーションによって発生した例外を失敗(failure)、予期せぬ例外をエラー(error)と呼んで区別しています。

この区別はJUnit 3 から JUnit 4 に引き継がれることはありませんでしたが、多くの JUnit 4 拡張ツールは、未だにこれを区別しています。

org.scalatest.junit.AssertionsForJUnit をミックスインすることで、JUnit ツールが、ScalaTest のアサーションの失敗を、エラーではなく失敗としてリポートするようになります。

verifyEasy で使用される JUnit のアサーションと、verifyFun で使用される ScalaTest アサーションの簡潔さの違いが見てとれます。 Scala コンパイラでこのクラスをコンパイルすると、JUnit は作成されたクラスファイルを適切に実行します。 コンパイルするには、以下のように入力します。

scalac -cp scalatest-1.5.jar:junit-4.4.jar ExampleSuite.scala

JUnit を使ってテストを実行するには、いくつか方法がありますが、たとえば以下のように入力します。

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar org.junit.runner.JUnitCore ExampleSuite JUnit version 4.4 .. Time: 0.046 OK (2 tests)

もし、JUnit でテストを実行するか、ScalaTest で実行するかを選択したいなら、org.scalatest.junit.JUnitSuite をミックスインするといいでしょう。 トレイト JUnitSuite は既に AssertionsForJUnit をミックスインしているので、このトレイトは必要ありません。

import org.scalatest.junit.JUnitSuite import scala.collection.mutable.ListBuffer import org.junit.Assert._ import org.junit.Test import org.junit.Before class ExampleSuite extends JUnitSuite { var sb: StringBuilder = _ var lb: ListBuffer[String] = _ @Before def initialize() { sb = new StringBuilder("ScalaTest は") lb = new ListBuffer[String] } @Test def verifyEasy() { // JUnit スタイルのアサーションを使用 sb.append("かんたん!") assertEquals("ScalaTest はかんたん!", sb.toString) assertTrue(lb.isEmpty) lb += "sweet" try { "verbose".charAt(-1) fail() } catch { case e: StringIndexOutOfBoundsException => // こうなるはず } } @Test def verifyFun() { // ScalaTest アサーションを使用 sb.append("たのしい!") assert(sb.toString === "ScalaTest はたのしい!") assert(lb.isEmpty) lb += "sweeter" intercept[StringIndexOutOfBoundsException] { "concise".charAt(-1) } } }

ExampleSuite は有効な JUnit のテストクラスなので、JUnit から実行できます。

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar org.junit.runner.JUnitCore ExampleSuite JUnit version 4.4 .. Time: 0.121 OK (2 tests)

しかし、ExampleSuite は ScalaTest の Suite でもあるので、ScalaTest からも実行できます。

$ scala -cp scalatest-1.5.jar:junit-4.4.jar org.scalatest.tools.Runner -p . -o -s ExampleSuite Run starting. Expected test count is: 2 ExampleSuite: - verifyFun - verifyEasy Run completed in 190 milliseconds. Total number of tests run: 2 Suites: completed 1, aborted 0 Tests: succeeded 2, failed 0, ignored 0, pending 0 All tests passed.

最後に、ScalaTest のマッチャーDSL を紹介します。 単純に ShouldMatchersForJUnit をミックスインしてください("should" より "must" の方が好き、という場合は MustMatchersForJUnit をミックスインしてください)。

import org.scalatest.junit.JUnitSuite import org.scalatest.junit.ShouldMatchersForJUnit import scala.collection.mutable.ListBuffer import org.junit.Test import org.junit.Before class ExampleSuite extends JUnitSuite with ShouldMatchersForJUnit { var sb: StringBuilder = _ var lb: ListBuffer[String] = _ @Before def initialize() { sb = new StringBuilder("ScalaTest は") lb = new ListBuffer[String] } @Test def verifyEasy() { // ScalaTest のアサーションを使う sb.append("かんたん!") assert(sb.toString === "ScalaTest はかんたん!") assert(lb.isEmpty) lb += "sweet" intercept[StringIndexOutOfBoundsException] { "concise".charAt(-1) } } @Test def verifyFun() { // ScalaTest のマッチャーを使う sb.append("たのしい!") sb.toString should be ("ScalaTest はたのしい!") lb should be ('empty) lb += "sweet" evaluating { "concise".charAt(-1) } should produce [StringIndexOutOfBoundsException] } }

前の例と同じく、このケースも JUnit 、ScalaTest 双方からテストを実行できます。

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar org.junit.runner.JUnitCore ExampleSuite JUnit version 4.4 .. Time: 0.136 OK (2 tests)

$ scala -cp scalatest-1.5.jar:junit-4.4.jar org.scalatest.tools.Runner -p . -o -s ExampleSuite Run starting. Expected test count is: 2 ExampleSuite: - verifyFun - verifyEasy Run completed in 182 milliseconds. Total number of tests run: 2 Suites: completed 1, aborted 0 Tests: succeeded 2, failed 0, ignored 0, pending 0 All tests passed.