EasyMockに触れる

EasyMockを使用するとモック(擬似)オブジェクトを使用したテストを行うことが
できるらしい。
また、モック(擬似)オブジェクトの目的は、インターフェースの使われ方をテストすることであり、スタブと混同するのは正しくないとのこと。ふーん。
①スタブ・・・例えば、データベース接続を伴うデータの取得処理を隠蔽し、DBの代わりに配列などでDBをシュミレートする。
また、アプリケーションの実行、ビルドを軽量化する。
②モック・・・API(インターフェース)が正しく呼び出されることを確認する。

でも、いまいち違いがピンと来ない。。。
EasyMockでも①でいうところのDBのシュミレートができそうだし・・・。

EasyMockのインストール

最新バージョン(今回はeasymock2.0)をEasyMockから取得する。
ちなみにeasymock2.0はJDK5.0が必要です。

EasyMockを使用したテストの手順

①モックオブジェクトの生成
②正常時の期待値の設定
 ※.モックオブジェクトへ振る舞いを記録する。
③モックテストの実施
④モックテストの検証
 ※.モックオブジェクトが記録した振る舞い通りに呼び出されたか検証する。

サンプルプログラム

テスト対象のプログラム

A・・・わざとResultSet#closeメソッドの呼び出しをコメントアウトしています。

package sample.easymock;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;

public class SampleDAO {
	public Map selectSample(Connection con, String sql) throws SQLException {
		Map result = null;
		Statement st = con.createStatement();
		ResultSet rs = st.executeQuery(sql);
		if(rs.next()) {
			result = new HashMap();
			result.put("sample", rs.getString(1));
		}
//		close()の呼び出しをコメントアウト	//A	
//		rs.close();
		st.close();
		return result;
	}
}
テストプログラム

B・・・verify(rsMock) の呼び出しでAssertionErrorがthrowされる

package sample.easymock;

import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import junit.framework.TestCase;

public class SampleDAOTest extends TestCase {

	private Connection conMock;
    private Statement stMock;
	private ResultSet rsMock;

	protected void setUp() {
		// ①Mockオブジェクトの生成
		conMock = createMock(Connection.class);
		stMock  = createMock(Statement.class);
		rsMock  = createMock(ResultSet.class);
    }
	/*
	 * Test method for 'sample.easymock.SampleDAO.selectSample(Connection, String)'
	 */
	public void testSelectSample() throws Exception {
		
		// ②期待値の設定
		expect(conMock.createStatement()).andReturn(stMock);
		expect(stMock.executeQuery("select * from sample")).andReturn(rsMock);
		expect(rsMock.next()).andReturn(false);

		rsMock.close();
		stMock.close();
		
		replay(conMock);
		replay(stMock);
		replay(rsMock);
		
		// ③モックテストの実施
		SampleDAO dao = new SampleDAO();
		dao.selectSample(conMock, "select * from sample");
		
		// ④モックテストの検証
		verify(conMock);
		verify(stMock);
		verify(rsMock); // B

	}
}

使ってみた感想としては、簡単に動的なモックオブジェクト(スタブと呼びたい・・)を
作成できてなかなか便利。
andReturnメソッドをうまく使えばやはりスタブとして利用できそう(^^;


複数回呼び出しの確認(expectLastCall().times(3))
テスト対象のプログラム
		if(rs.next()) {
			result = new HashMap();
			result.put("sample1", rs.getString(1));
			result.put("sample2", rs.getString(1));
			result.put("sample3", rs.getString(1));
		}
テストプログラム
		expect(conMock.createStatement()).andReturn(stMock);
		expect(stMock.executeQuery("select * from sample")).andReturn(rsMock);
		expect(rsMock.next()).andReturn(true);
		expect(rsMock.getString(1)).andReturn("hello");
		expectLastCall().times(3);