【Java】JUnitでCalendarクラスの日付をMock化する方法

JUnitでテストコードを書くうえでやっかいになる存在、それは現在時刻を扱っているところですよね。

テストコードを動かすたびに毎回値が変わるとテストコードを書く方としては大変です。今回はそんな悩みを解決するためにCalendarクラスの日付をJUnit内で固定にする方法を紹介していきます!

今回の方法はJUnit4で検証しています。

[スポンサーリンク]

このクラスをテストするよ

今回JUnitでテストする対象のクラスはコチラ!
getDateメソッドで現在時刻を返すというメソッドです。これでは動かすたびに毎回値がかわってきますね。

public class ExampleUtil {

    public static Date getDate() {
        Calendar cal = Calendar.getInstance();
        return cal.getTime();
    }
}

まずはPowerMockitoを使えるようにしよう

Pom.xmlへこちらのdependencyを追加してPowerMockitoが使えるようにします。

<!-- https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4 -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>1.6.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.6</version>
</dependency>

JUnitを使ったテスト

それでは、さきほどのExampleUtilをJUnitを使ってテストしていきます。

JUnit内ではPowerMockitoを使って、プログラムがCalendar.getInstanceを実行した時に返却する値を固定値として設定しています。
色々importしないといけないのでこちらも省略せずにのこしておきます。

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ExampleUtil.class, Calendar.class})
public class ExampleUtilTest {

    @Test
    public void DateTest() {
        SimpleDateFormat sdf =
                new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
        Calendar cal = Calendar.getInstance();
        cal.set(2017, 4, 22, 10, 10, 10);
   
        PowerMockito.mockStatic(Calendar.class);
        PowerMockito.when(Calendar.getInstance()).thenReturn(cal);
        Date result = ExampleUtil.getDate();
   
        System.out.println("Date : "+ sdf.format(result));
        assertThat(sdf.format(result), is(sdf.format(cal.getTime())));
    }
}

11行目を見てください。モック対象のクラスだけではなくて、テスト対象のクラスも@PrepareForTestへ定義する必要があります。気をつけて下さい。

じつは、これを忘れてしまってハマりました。。その時参考にしたサイトはコチラです。

Javaのバージョン

今回検証したjavaのバージョンは8です。
JUnitはバージョン4です。

さいごに

これでJUnitを動かすたびに現在時刻がコロコロとかわるということは避けることができましたね。

PowerMockitoはstaticクラスにも対応しているので色々な場面で使えそうです。自分で作ったstaticクラスをモック化したいというときなんかでもどんどん使っていきましょう!

それでは!