Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

ScalaでTestNGのテストをする

Javaで書いたこういうTestNGのテストがある。

import static org.testng.Assert.assertEquals;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class TestNGSample {
	private Target target;

	@Test
	public void verifyAdd1() {
		System.out.println("★★★verifyAdd1()を呼び出した★★★");
		int result = target.add(1, 2);
		assertEquals(result, 3);
	}

	@BeforeMethod
	public void init() {
		System.out.println("★★init()を呼び出した★★");
		target = new Target();
	}

	@Test(expectedExceptions = { java.lang.RuntimeException.class })
	public void exceptionTest() {
		System.out.println("★★★exceptionTest()を呼び出した★★★");
		target.throwException();
	}
}

これをScalaで書き直して実行する。
Targetクラスは足し算するメソッドがあるだけのクラスね。

まずScalaで書き直す。

import org.testng.annotations.{BeforeMethod, Test}
import org.testng.TestNG
import org.testng.TestListenerAdapter
import org.testng.Assert._

class TestNGSample {

  var target:Target = null
  
  @BeforeMethod
  def init() = {
    target = new Target
    Console println "★init()を呼び出した★"
  }
  
  @Test
  def verifyAdd1() = {
    Console println "★★★verifyAdd1()を呼び出した★★★"
    val result = target add(1, 2)
    assertEquals(result, 3)
  }

  @Test{val expectedExceptions = Array(classOf[RuntimeException])}
  def exceptionTest() = {
    Console println "★★★exceptionTest()を呼び出した★★★"
    target throwException
  }
}

import文

import文はJavaと同じ。クラスパスさえ通せばScalaからJavaクラスは普通に使えます。
同じパッケージにある複数のクラスをインポートするときは{}にカンマ区切りでクラスを指定。
「_」はJavaでいう「*」。


Scalaにはstaticという概念がないので(すべてがオブジェクトだから?)、static importはない。
「import org.testng.Assert._」はAssertクラスのstaticメソッドをすべてインポートしてる。

varとval

varとvalはScalaの説明でどこでも載ってるけど、valは一度代入すると変更できない。varは今までの変数と同じ。
Scalaには型推論(注:動的言語ではないので、型がないわけではありません)があるので、変数の型は指定しなくて「も」いい。
指定したければ「var target:Target」のようにコロンの後に型を書く。

テストの実行

Scalaで書いたTestNGのテストは、特に違いなく実行できる。
これはScalaをコンパイルするとclassファイルができるからかな?
まずはmainメソッドからテストを実行することにしよう。

import org.testng.TestNG

object Main {
  def main(args: Array[String]): Unit = {
    val testng = new TestNG
    testng setTestClasses(Array(classOf[TestNGSample]))
    testng run
  }
}

Javaでいうmainメソッドは「main(args: Array[String]): Unit」のシグニチャ
UnitはJavaのvoid(と最初は考えていていいそうだ)。Scalaでは戻り値はコロンの後ろ。
これを実行するとテストが実行される。

[Parser] Running:
  Command line suite

★init()を呼び出した★
★★★exceptionTest()を呼び出した★★★
★init()を呼び出した★
★★★verifyAdd1()を呼び出した★★★

===============================================
Command line suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

classとobject

気をつけてほしいのは、Mainの方はclassではなくobjectというキーワードを使っていること。
これもScalaの説明でどこでも載ってるけど、objectとするとシングルトンオブジェクトになる。
(自分でnewしてインスタンスは作れなくなる)
mainメソッドを定義するにはclassではなくobjectでないとダメみたい。
「Exception in thread "main" java.lang.NoSuchMethodError: main」と出たので。

eclipseからテストを実行

eclipseにTestNGプラグインを入れていれば、それを使ってテストを実行することもできる。
1つはまった。
eclipseのRun Configurationsで、Annotation Compliance Levelが「JDK」になってるか確認すること。
Scalaで書いているからきちんとプラグインが認識してくれず、「javadoc」がデフォルトになってしまうので。
f:id:jyukutyo:20081017150424p:image
テスト結果も普通にビューに出る。
f:id:jyukutyo:20081017150425p:image

[Parser] Running:
  /Users/jyukutyo/Documents/workspace/ScalaSample/temp-testng-customsuite.xml

★init()を呼び出した★
★★★exceptionTest()を呼び出した★★★
★init()を呼び出した★
★★★verifyAdd1()を呼び出した★★★
PASSED: exceptionTest
PASSED: verifyAdd1

===============================================
    sample.TestNGSample
    Tests run: 2, Failures: 0, Skips: 0
===============================================


===============================================
ScalaSample
Total tests run: 2, Failures: 0, Skips: 0
===============================================