テストクラスを書くときに使いそうなので事前に調査した。
調べたのは下記の通り
- Springを使ってるのでDIしている箇所がモックにできるか
- staticメソッドの戻りもモックにできるか
- new Date()...の戻り値もモックにできるか
結論:できた。
これ1つで全部まかなえたのは結構大きいかもしれない。できないことはなんだろうか??
テストクラス
package com.hachiyae.jmockit;
import mockit.Expectations;
import mockit.Mock;
import mockit.MockUp;
import org.junit.Test;
import java.util.Calendar;
import java.util.Date;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class TesterServiceTest {
private TesterService tester = new TesterService();
@Test
public void testSayHello() throws Exception {
String message = tester.sayHello("user1");
assertThat(message, is("Hello user1"));
}
// // これでもOK
// @Mocked
// private CurrentDateFactory currentDateFactory;
// 引数でもいいよ
@Test
public void testSayCurrentDate(final CurrentDateFactory currentDateFactory) throws Exception {
new Expectations() {
// ここにつけてもいいよ
// CurrentDateFactory currentDateFactory;
{
setField(tester, currentDateFactory);
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2014, 0, 1);
// 直後にresultに値を入れることでモックの戻り値を定義
// timesは回数(1の時は省略
currentDateFactory.getCurrentDate(); result = calendar.getTime(); times = 1;
}
};
String message = tester.sayCurrentDate();
assertThat(message, is("current date is 2014/01/01"));
}
@Test
public void testSayCurrentTime() throws Exception {
// static method
new Expectations() {
// 無駄にモックオブジェクトインスタンスを生成しない
final TestUtils testUtils = null;
{
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(2014, 0, 1, 1, 2, 3);
testUtils.getCurrentDate(); result = calendar.getTime();
}
};
String message = tester.sayCurrentTime();
assertThat(message, is("current time is 01:02:03"));
}
@Test
@SuppressWarnings({"unused", "deprecation"})
public void testSayCurrentYear() throws Exception {
new MockUp<System>() {
@Mock
public long currentTimeMillis() {
return new Date(110, 0, 1).getTime();
}
};
String message = tester.sayCurrentYear();
assertThat(message, is("current year is 2010"));
}
}
テスト対象クラス
package com.hachiyae.jmockit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class TesterService {
@Autowired
private CurrentDateFactory currentDateFactory;
public String sayHello(String userName) {
return "Hello " + userName;
}
public String sayCurrentDate() {
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
return "current date is " + format.format(currentDateFactory.getCurrentDate());
}
public String sayCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
return "current time is " + format.format(TestUtils.getCurrentDate());
}
public String sayCurrentYear(){
SimpleDateFormat format = new SimpleDateFormat("yyyy");
Date date = new Date();
return "current year is " + format.format(date);
}
}
テスト対象クラスから呼ばれるService
package com.hachiyae.jmockit;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class CurrentDateFactory {
public Date getCurrentDate(){
return new Date();
}
}
テスト対象クラスから呼ばれるstatic
package com.hachiyae.jmockit;
import java.util.Date;
public class TestUtils {
public static Date getCurrentDate (){
return new Date();
}
}
参考URL:
- JMockit
https://code.google.com/p/jmockit/ - 次世代のモックフレームワークであるJMockitの基本的な使い方 http://d.hatena.ne.jp/ryoasai/20110107/1294427245
- How to mock the default constructor of the Date class with JMockit? http://stackoverflow.com/questions/4563584/how-to-mock-the-default-constructor-of-the-date-class-with-jmockit