Spring FrameworkのUnitテスト実装方法 2-2.Serviceテスト(Junit4, MockClass)
TERASOLUNA Server Framework for Java (5.x) Development Guideline
サンプルソースはこちら
(これのMyBatis3を使用したパターンで作成してます。)
2-2.Serviceテスト Junit4ライブラリを使用したパターン
Serviceクラスのテストです。
Repositoryクラスのメソッドをモック化してテストしています。
モック用にクラスを新たに作成して、そのメソッドに置き換えるという流れです。
【pom.xml】
Junitライブラリが必要です。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
【テスト対象クラス】
TodoServiceImpl.java
テスト対象はfinishメソッド
@Service
@Transactional
public class TodoServiceImpl implements TodoService {
private static final long MAX_UNFINISHED_COUNT = 5;
@Inject
TodoRepository todoRepository;
public Todo findOne(String todoId) {
Todo todo = todoRepository.findOne(todoId);
if (todo == null) {
ResultMessages messages = ResultMessages.error();
messages.add(ResultMessage.fromText("[E004]The requested Todo is not found. (id=" + todoId + ")"));
throw new ResourceNotFoundException(messages);
}
return todo;
}
@Override
public Todo finish(String todoId) {
// TODO 自動生成されたメソッド・スタブ
Todo todo = findOne(todoId);
if (todo.isFinished()) {
ResultMessages messages = ResultMessages.error();
messages.add(ResultMessage.fromText("[E002]The requested Todo is already finished. (id=" + todoId + ")"));
throw new BusinessException(messages);
}
todo.setFinished(true);
todoRepository.update(todo);
return todo;
}
}
モック化の対象メソッドは、todoRepository.updateメソッドとtodoRepository.findOneメソッドになります。
今回のテスト対象クラスのfinishメソッドでは内部メソッドのfindOneメソッドを呼んでいるのですが、
内部メソッドもモック化して純粋にfinishメソッドのみのテストがしたいという場合はPowerMockとか使って無理やりモック化する方法があります。でも今回はやりません。
【テストクラス】
TodoServiceImplTestVerMockClass.java
public class TodoServiceImplTestVerMockClass {
TodoServiceImpl target;
@Before
public void setUp() throws Exception{
//テストメソッドでモックを切り替えるため処理なし
}
//正常に動作したパターン
@Test
public void testFinishOK() throws Exception{
//モッククラスの適用(TestFinishOKMock)
target = new TodoServiceImpl();
TodoRepository mockTodoRepository = new TestFinishOKMock();
target.todoRepository = mockTodoRepository;
//引数設定
String todoId = "cceae402-c5b1-440f-bae2-7bee19dc17fb";
//finishメソッドのテスト
Todo todo = target.finish(todoId);
//結果検証(assertTodoメソッドはメソッドの実行によって返ってきたTodoオブジェクトを検証するメソッド)
assertTodo(todo);
}
//取得したTodoオブジェクトのfinishedが既にtrueで異常が発生したパターン
//@Testのexpectedには期待するExceptionクラスを設定する。こうすることでExceptionが発生することは想定通りということを宣言している。
@Test(expected = BusinessException.class)
public void testFinishNG() throws Exception{
//モッククラスの適用(TestFinishNGMock)
target = new TodoServiceImpl();
TodoRepository mockTodoRepository = new TestFinishNGMock();
target.todoRepository = mockTodoRepository;
//引数設定
String todoId = "cceae402-c5b1-440f-bae2-7bee19dc17fb";
//try-catch文はなくてもJunitとしては正常になるが、printStackTraceメソッドでエラーの内容を表示させている。
try {
target.finish(todoId);
}catch (BusinessException e) {
// TODO: handle exception
e.printStackTrace();
throw e;
}
}
}
想定通りにデータを取ってきた時のパターンと、
異常が発生した時のパターンの2パターンを記述しました。
期待通りの異常が発生した場合は @Test(expected = Exceptionクラス)と設定することで、Junitのテストが成功になります。
【その他設定】
TestFinishOKMock.java
testFinishOK()メソッドでテストする対象のモックです。
public class TestFinishOKMock implements TodoRepository {
//finishedにfalseが入ったデータを返すモック
@Override
public Todo findOne(String todoId) {
Todo todo = new Todo();
todo.setTodoId("cceae402-c5b1-440f-bae2-7bee19dc17fb");
todo.setTodoTitle("one");
todo.setFinished(false);
try {
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String strDate = "2017-10-01 15:39:17.888";
Date date1 = sdFormat.parse(strDate);
todo.setCreatedAt(date1);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return todo;
}
//trueを返すモック
@Override
public boolean update(Todo todo) {
return true;
}
}
TestFinishNGMock.java
testFinishNG()メソッドでテストする対象のモックです。
public class TestFinishNGMock implements TodoRepository{
@Override
public Todo findOne(String todoId) {
Todo todo = new Todo();
todo.setTodoId("cceae402-c5b1-440f-bae2-7bee19dc17fb");
todo.setTodoTitle("one");
todo.setFinished(true);
try {
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String strDate = "2017-10-01 15:39:17.888";
Date date1 = sdFormat.parse(strDate);
todo.setCreatedAt(date1);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return todo;
}
//trueを返すモック
@Override
public boolean update(Todo todo) {
return true;
}
}
あらかじめfinishメソッド対象のデータをtrueとしておくことで異常を発生させる。
まーシンプルですよね。Springの機能一切関係なくて純粋にjavaのクラスそのもののテストをしているって感じです。
サンプルソースはgithubで公開してます。
Spring Unit Test pattern9


コメントを書く