mockito(1) スタブ的に使う

DAO依存のクラステストが面倒

テスト対象のクラスAがDAOクラスBに依存しているような場合、テストデータをDBにあらかじめ登録する必要がある。
dbunitのようなファイルからレコードを読み込むフレームワークはあるが、DAOではないクラスAのテストのためにレコードを仕込むのは面倒。

mockitoを使う

レコードをいちいち仕込むのは面倒なのでスタブを作成して、実際のメソッドをテストデータ呼び出しのメソッドに置き換える。
ここでmockitoフレームワークを使用する。

準備

今回はmavenを使用せず、手作業でライブラリを導入する。
公式から下記をダウンロード。

    1. mockito-core-2.0.29-beta.jar

mavenリポジトリにアクセスして、依存するライブラリをダウンロード。
依存関係にあるライブラリは「maven-metadata.xml」参照。

    1. byte-buddy-0.6.11.jar
    2. objenesis-2.1.jar

ビルドパスに外部jarとして追加。

実際に使ってみる

Userテーブルを操作するUserDaoとUserDaoを使用するUserLogicを用意。
ここではUserDaoをモックして、テストデータを返すようにした。
モックの作成方法、注入方法は複数あるが、下記以外はモックが注入されないなどうまくいかなかった。

UserLogicテストケース。

package jp.ne.hatena.matasaburou.logic;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.ArrayList;
import java.util.List;

import jp.ne.hatena.matasaburou.dao.UserDao;
import jp.ne.hatena.matasaburou.entity.UserEntity;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class UserLogicTest{

	@Mock
	private UserDao dao;

	@InjectMocks
	private UserLogic target;

	@Before
	public void setup(){
		MockitoAnnotations.initMocks(this);
	}

	@Test
	public void test_findAll_ok() throws Exception{
		List<UserEntity> list = new ArrayList<>();
		list.add(createEntity("takeda",0));
		list.add(createEntity("sanada", 1));
		when(dao.findAll()).thenReturn(list);

		List<UserEntity> result = target.findAll();
		assertEquals(2, result.size());
	}

	public UserEntity createEntity(String name, int sex){
		UserEntity entity = new UserEntity();
		entity.setName(name);
		entity.setSex(sex);
		return entity;
	}

}

UserDaoクラス。(適当)

package jp.ne.hatena.matasaburou.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;

import jp.ne.hatena.matasaburou.common.dao.AbstractDao;
import jp.ne.hatena.matasaburou.entity.UserEntity;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

public class UserDao extends AbstractDao {
	public int insert(UserEntity entity) throws Exception{
		Class.forName("org.mariadb.jdbc.Driver");
		Connection con = DriverManager.getConnection("jdbc:mariadb://localhost:3306/daotraining", "root", "root");
		QueryRunner q = new QueryRunner();

		List<Object> fieldValue = new ArrayList<Object>();
		fieldValue.add(entity.getName());
		fieldValue.add(entity.getSex());

		int result = q.update(con, "insert into user (name, sex) values(?, ?)", fieldValue.toArray());

		return result;
	}

	public List<UserEntity> findAll() throws Exception{
		Class.forName("org.mariadb.jdbc.Driver");
		Connection con = DriverManager.getConnection("jdbc:mariadb://localhost:3306/daotraining", "root", "root");
		QueryRunner q = new QueryRunner();
		ResultSetHandler handler = new BeanListHandler(UserEntity.class);
		List<UserEntity> list = (List<UserEntity>)q.query(con, "SELECT * FROM USER", handler);

		return list;
	}
}

UserLogicクラス。(適当)

package jp.ne.hatena.matasaburou.logic;

import java.security.InvalidParameterException;
import java.util.List;

import jp.ne.hatena.matasaburou.dao.UserDao;
import jp.ne.hatena.matasaburou.entity.UserEntity;

public class UserLogic {

	private UserDao dao;

	public UserLogic() {
		dao = new UserDao();
	}

	public void insertData(UserEntity entity) throws Exception{
		if(entity == null){
			throw new InvalidParameterException("entity is null.");
		}

		int result = dao.insert(entity);

		if(result != 1){
			throw new Exception("insert userData failed.");
		}
	}

	public List<UserEntity> findAll() throws Exception{
		return dao.findAll();
	}

}

UserEntityクラス

package jp.ne.hatena.matasaburou.entity;

public class UserEntity {

	private long no;
	private String name;
	private Integer sex;

	public long getNo() {
		return no;
	}
	public void setNo(long no) {
		this.no = no;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getSex() {
		return sex;
	}
	public void setSex(Integer sex) {
		this.sex = sex;
	}
}