Fight the Future

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

プレゼン、ボランティアコーチします!

勉強会でスピーカーをやりたいけど、プレゼンが初めて、苦手という方に無償でコーチします!資料レビューや録画リハへアドバイスします。Twitter@jyukutyoまでメンションでもDMでも。

私はデブサミやJJUG CCCなど200人規模で経験ありです。海外も短いながら経験あり。デブサミ2017では公募スピーカー1位でした!

TestNGでXMLを使わずにテストを実行する

TestNGではtestng.xml(ファイル名は任意)というXMLを使ってテストを実行するのですが、
XMLを使わずにプログラミングでテストを実行することもできます。

	public static void main(String[] args) {
		TestNG testNG = new TestNG();

		testNG.addListener(new DbUnitNGTestListener());
		testNG.addListener(new PerformanceListener());
		TestListenerAdapter adapter = new TestListenerAdapter();
		testNG.addListener(adapter);

		testNG.setTestClasses(new Class[] { PerformanceTest.class });

		testNG.run();

		System.out.println("PassedTests:" + adapter.getPassedTests());
		System.out.println("FailedTests:" + adapter.getFailedTests());
		System.out.println("SkippedTests:" + adapter.getSkippedTests());

	}

TestNGオブジェクトを生成して、run()メソッドを呼ぶことでテストを実行します。
リスナークラスを追加することもできます。
ただ、普通にrun()を呼び出しただけでは、テスト成功と失敗が数でしかわかりません。
こんな感じで。

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

なので、詳細に出力するためにはTestListenerAdapterオブジェクトをリスナーとして登録します。
TestListenerAdapterはTestNGが提供するクラスで、テスト結果に関するさまざまな情報を取り出すことができます。
このサンプルでは成功、失敗、スキップしたテストをコンソールに出力してます。

PassedTests:[[TestResult: testPerformance STATUS:1 METHOD:org.dbunitng.sample.PerformanceTest.testPerformance()]]
FailedTests:[]
SkippedTests:[]

XMLの設定をプログラミングする

ですが、TestNGクラスには、XMLで記述できたパラメータなどを設定するメソッドはありません。

<parameter name="driver" value="com.mysql.jdbc.Driver"></parameter>
<parameter name="url" value="jdbc:mysql://127.0.0.1/testframework"></parameter>
<parameter name="username" value="root"></parameter>
<parameter name="password" value="root"></parameter>

パラメータをプログラミングで設定するためには、XmlSuiteオブジェクトを利用します。

	public static void main(String[] args) {
		TestNG testNG = new TestNG();

		testNG.addListener(new DbUnitNGTestListener());
		TestListenerAdapter adapter = new TestListenerAdapter();
		testNG.addListener(adapter);

		testNG.setTestClasses(new Class[] { DbUnitNGAnnotationTest.class });

		XmlSuite suite = new XmlSuite();
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put("driver", "com.mysql.jdbc.Driver");
		parameters.put("url", "jdbc:mysql://127.0.0.1/testframework");
		parameters.put("username", "root");
		parameters.put("password", "root");
		parameters.put("defaultOperation", "CLEAN_INSERT");
		suite.setParameters(parameters);

		testNG.setXmlSuites(Arrays.asList(new XmlSuite[] { suite }));

		testNG.run();

		System.out.println("PassedTests:" + adapter.getPassedTests());
		System.out.println("FailedTests:" + adapter.getFailedTests());
		System.out.println("SkippedTests:" + adapter.getSkippedTests());

	}

XmlSuiteオブジェクトを生成し、Mapでパラメータを表します。
MapをXmlSuiteにセットし、TestNGオブジェクトにXmlSuiteをセットします。
ただ、これでは例外が発生します。

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:151)
	at java.util.AbstractList.add(AbstractList.java:89)
	at org.testng.TestNG.initializeCommandLineSuites(TestNG.java:630)
	at org.testng.TestNG.run(TestNG.java:690)

どうやらArrays.asList()で生成したリストに対してTestNGが内部で要素を追加しようとしたようです*1
なので、こうしました。

	public static void main(String[] args) {
		TestNG testNG = new TestNG();

		testNG.addListener(new DbUnitNGTestListener());
		TestListenerAdapter adapter = new TestListenerAdapter();
		testNG.addListener(adapter);

		testNG.setTestClasses(new Class[] { DbUnitNGAnnotationTest.class });

		XmlSuite suite = new XmlSuite();
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put("driver", "com.mysql.jdbc.Driver");
		parameters.put("url", "jdbc:mysql://127.0.0.1/testframework");
		parameters.put("username", "root");
		parameters.put("password", "root");
		parameters.put("defaultOperation", "CLEAN_INSERT");
		suite.setParameters(parameters);

		List<XmlSuite> list = new ArrayList<XmlSuite>();
		list.add(suite);
		testNG.setXmlSuites(list);

		testNG.run();
// the rest is ommitted...

しかし、それでも例外が発生します。

Exception in thread "main" org.dbunitng.exception.DbUnitNGRuntimeException: Required Parameters are not specified in TestNG Suite.
org.dbunitng.listeners.internal.DbUnitNGConfig@1dddba[
  driver=<null>
  url=<null>
  userName=<null>
  password=<null>
  isDbcp=false
  schema=<null>
  factory=<null>
  defaultOperation=NONE
]

Mapで設定したパラメータが取得できないようです。
テストでパラメータを利用したい場合、TestNG#setTestClasses()でテストクラスをセットするのではなく、XmlTest#setXmlTestClasses()を使う必要があるようです。


なので、最終的にパラメータを設定したテストは次のようになります。

	public static void main(String[] args) {
		TestNG testNG = new TestNG();

		testNG.addListener(new DbUnitNGTestListener());
		TestListenerAdapter adapter = new TestListenerAdapter();
		testNG.addListener(adapter);

		XmlSuite suite = new XmlSuite();
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put("driver", "com.mysql.jdbc.Driver");
		parameters.put("url", "jdbc:mysql://127.0.0.1/testframework");
		parameters.put("username", "root");
		parameters.put("password", "root");
		parameters.put("defaultOperation", "CLEAN_INSERT");
		suite.setParameters(parameters);

		XmlTest test = new XmlTest(suite);
		XmlClass[] classes =
			new XmlClass[] { new XmlClass(DbUnitNGAnnotationTest.class) };
		test.setXmlClasses(Arrays.asList(classes));

		List<XmlSuite> list = new ArrayList<XmlSuite>();
		list.add(suite);
		testNG.setXmlSuites(list);

		testNG.run();
// the rest is ommitted...

これでセットしたパラメータを用いてテストを実行できます。

*1:Arrays.asList()が生成するリストは不変リスト