テスト対象クラス内でnewで生成されている依存オブジェクトをモックする
テスト対象クラス(DateUtil.java)
import java.text.SimpleDateFormat; import java.util.Date; public class DateUtil { public static String getCurrentDate() { Date d = new Date(); return new SimpleDateFormat("yyyy/MM/dd").format(d); } }
テストクラス(DateUtilTest.java)
import static org.hamcrest.core.Is.*; import static org.junit.Assert.*; import java.util.Calendar; import java.util.Date; import mockit.Mock; import mockit.MockUp; import mockit.integration.junit4.JMockit; import org.junit.Test; import org.junit.runner.RunWith; // new Objectをモックするテスト @RunWith(JMockit.class) public class DateUtilTest { @Test public void testGetCurrentDate() { // 期待値は2015/05/05 Calendar c = Calendar.getInstance(); c.set(2015, 4, 5); Date expected = c.getTime(); // 記録フェーズ new MockUp<Date>() { @Mock public void $init() { this.getMockInstance().setTime(expected.getTime()); } }; // リプレイフェーズ String strDate = DateUtil.getCurrentDate(); // 検証フェーズ assertThat(strDate, is("2015/05/05")); } }
コンストラクタのモックはExpectations APIだとできないみたいで、Mockups APIを使う必要があります。
これが出来るのがJMockitの強みかと思っていたのですが、JMockitのページ読んでたら、PowerMock(Mockito)でも出来るみたいです。
PowerMock(Mockito)版テストクラス(DateUtilTest.java)
import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.powermock.api.mockito.PowerMockito.*; import java.util.Calendar; import java.util.Date; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; // new Objectをモックするテスト @RunWith(PowerMockRunner.class) @PrepareForTest(DateUtil.class) public class DateUtilTest { @Test public void testGetCurrentDate() throws Exception { // 期待値は2015/05/05 Calendar c = Calendar.getInstance(); c.set(2015, 4, 5); Date expected = c.getTime(); // 記録フェーズ Date dateMocked = mock(Date.class); whenNew(Date.class).withNoArguments().thenReturn(dateMocked); when(dateMocked.getTime()).thenReturn(expected.getTime()); // リプレイフェーズ String strDate = DateUtil.getCurrentDate(); // 検証フェーズ assertThat(strDate, is("2015/05/05")); } }
どっちが良いのかは好みもあるのでしょうが、個人的には、テスト対象クラス(DateUtil.java)をクラスレベルで宣言(@PrepareForTest(DateUtil.class))しなければならない、PowerMock(Mockito)はイマイチかなあと思います。
あとは、依存jarが一つで済むJMockitの方が身軽で良いかなあと。