Fight the Future

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

TestNG+DbUnitライブラリのパフォーマンス

5000件をBeanのListで取得して、XMLの期待値と比較するパフォーマンステストをやってみました。
こういうのって一概に参考にならないことも多いと思うんですけど、感触だけでも伝えられたらって感じです。

こんなテーブルに5000件入れます。

mysql> desc emp;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| EMPNO    | int(11)     | NO   | PRI | NULL    |       | 
| ENAME    | varchar(10) | YES  |     | NULL    |       | 
| JOB      | varchar(9)  | YES  |     | NULL    |       | 
| MGR      | int(11)     | YES  |     | NULL    |       | 
| HIREDATE | date        | YES  |     | NULL    |       | 
| SAL      | float(7,2)  | YES  |     | NULL    |       | 
| COMM     | float(7,2)  | YES  |     | NULL    |       | 
| DEPTNO   | int(11)     | YES  | MUL | NULL    |       | 
+----------+-------------+------+-----+---------+-------+

データはこんなのです。期待値のXMLです。

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
  <EMP EMPNO="1" ENAME="SMITH" JOB="CLERK" MGR="7902" HIREDATE="1980-12-17" SAL="800.0" DEPTNO="20"/>
...follow similar elements
</dataset>

こういうテストです。

  • テーブルをCLEAN_INSERTして5000件のデータを入れる。
  • DAOから5000件をリストで取得する
  • リストをデータセットに変換し、XMLの期待値とアサーションする

DAOは内部でiBatisを使ってデータを取得してます。


実行結果はこうでした!

Test Suite starts.
DAO execute time : (381 ms)
PASSED: testPerformance

Test Suite ends.
execute time : (14359 ms)

テスト全体での実行時間は14秒ちょい(3回実行してもほぼこの時間でした)。
DAOのメソッドを呼び出す前後で時間を計測しましたが、それが0.4秒なので、
CLEAN_INSERTして、データセットへの変換とアサーションで14秒かかってます。


5000件でこの実行時間なら十分許容範囲じゃないです?
まさかユニットテストで5000件入れることはないし、
結合テストとかならビルドマシンやデイリービルドで実行するので、
十分実用にたえると思います。


以下実行環境や詳しいテスト内容を記述します。

僕のマシンスペックはこうです。

  • プロセッサ名: Intel Core 2 Duo
  • プロセッサ速度: 2.4 GHz
  • プロセッサ数: 1
  • 合計コア数: 2
  • 二次キャッシュ: 3 MB
  • メモリ: 2 GB

MySQLのバージョンです。

mysql> select version();
+-------------+
| version()   |
+-------------+
| 5.0.51b-log | 
+-------------+

テストクラスです。

package org.dbunitng.sample.test;

import java.util.List;

import org.dbunit.DatabaseUnitException;
import org.dbunitng.annotations.DatabaseOperationType;
import org.dbunitng.annotations.SetUpOperation;
import org.dbunitng.assertion.AssertionHelper;
import org.dbunitng.dataset.BeanListConverter;
import org.dbunitng.sample.dao.EmpDao;
import org.dbunitng.sample.entity.Emp;
import org.testng.annotations.Test;

@Test(groups = "performance")
public class PerformanceTest {

	@SetUpOperation(value = DatabaseOperationType.CLEAN_INSERT, pathname = "org/dbunitng/sample/test/result.xml")
	public void testPerformance() throws DatabaseUnitException {
		EmpDao dao = new EmpDao();
		long start = System.currentTimeMillis();
		List<Emp> list = dao.listAllEmployee();
		System.out.printf("DAO execute time : (%d ms)\n", System.currentTimeMillis() - start);

		AssertionHelper.assertEqualsOnlyColumnsInFile(new BeanListConverter(
			list).convert(), getClass(), "result.xml");
	}

}

実行時間を計測するリスナークラスです。

package org.dbunitng.sample.test;

import org.testng.ISuite;
import org.testng.ISuiteListener;

public class PerformanceListener implements ISuiteListener {

	private long start;

	public void onStart(ISuite suite) {
		System.out.println("Test Suite starts.");
		start = System.currentTimeMillis();
	}

	public void onFinish(ISuite suite) {
		System.out.println("Test Suite ends.");
		System.out.printf("execute time : (%d ms)", System.currentTimeMillis()
			- start);
	}

}