JUnitでシステム日付けを固定する方法
システム日付けを固定したい
仕事で単体試験フェーズになった時、日付けを固定したいという場面はよくでてくる。
今回はMockライブラリを用いて時間を固定してみた。
前提 テスト対象のクラスは??
今回は下記をテストするJUnitを記述することにする。
public class OutputDate {
public void getDate(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh時mm分ss秒SSSミリ秒");
System.out.println(sdf.format(new Date()));
}
}
上手くいけばnew Date()で出力される日時が固定されるはず!
まずはPowerMock!
上司に教えてもらい下記のような方法で実現できることを知った。
@RunWith(PowerMockRunner.class)
@PrepareForTest({OutputDate.class, Date.class})
public class FixSysDateUsingPowerMock1 {
OutputDate output = new OutputDate();
@Before
public void setUp(){
setDatemock();
}
@Test
public void test() {
output.getDate();
}
/**
* システム日付けを固定する
* この方法だとミリ秒まで固定できない
*/
private static void setDatemock(){
Calendar cal = Calendar.getInstance();
//時間を2018年1月1日10時10分10秒にセットする(月は0が1月)
cal.set(2018, 0,1,10,10,10);
try {
PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(cal.getTime());
when(new Date()).thenReturn(cal.getTime());
} catch (Exception e) {
e.printStackTrace();
}
}
setDatemock()メソッドでCalendarクラスのset()メソッドを用いて固定化を試みている方法である。最初はこれでいいやと思ったのだが、これだとミリ秒を固定できない。setメソッドでミリ秒まで指定するものが無いから(自分が探した範囲では)である。
PowerMockでミリ秒まで出したい、、
どうしようか悩んでいたところ、文字列でうまくできないかな?という上司からのヒントのもと、以下の方法を思いついた。
@RunWith(PowerMockRunner.class)
@PrepareForTest({ OutputDate.class, Date.class })
public class FixSysDateUsingPowerMock2 {
OutputDate output = new OutputDate();
@Before
public void setUp() {
setDatemock();
}
@Test
public void test() {
output.getDate();
}
/**
* システム日付けを固定する
* この方法だとミリ秒まで固定する
*/
private static void setDatemock() {
String strDate = "2018-01-01 10:10:10.111";
// 時間を2018年1月1日10時10分10秒にセットする(月は0が1月)
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
try {
PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(sdFormat.parse(strDate));
when(new Date()).thenReturn(sdFormat.parse(strDate));
} catch (Exception e) {
e.printStackTrace();
}
}
固定したい日時を、文字列からDate形に無理やり変換する方法である。
この方法で、ミリ秒も固定することができた。
めでたしめでたし、、、
JMockitで日時固定できないかな?
上記の方法ですっかり安心していたのだが、カバレッジ取得の際に少し困る問題が発生した。
Eclipseでカバレッジを取得する時に使用するツール「Eclemma」がテストランナーでPowerMockRunner.classを指定すると上手く動作しないようなのである。
既知の問題らしく、一応以下の方法のように@Ruleを使用する方法で解決するらしい。
PowerMockを使ってEclemmaでカバレッジも取得する方法はこちら→https://code.i-harness.com/ja/q/1647e8c
しかし、単体試験時の自分はせっかくだし別の方法ないかな~と模索してた。
そしてJMockitライブラリを使用して下記の方法を思いついた。
@RunWith(JMockit.class)
public class FixSysDateUsingJMockit {
//private staticをつけないとダメ
@Mocked
private static OutputDate output = new OutputDate();
@Before
public void setUp() throws Exception{
setDatemock();
}
@Test
public void test() {
output.getDate();
}
private void setDatemock() throws Exception {
String strDate = "2018-01-01 10:10:10.111";
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
new CurrentTimeMock(sdFormat.parse(strDate));
}
/**
* dateモック用クラス
*/
public static class CurrentTimeMock extends MockUp<System>{
Date mockTime;
public CurrentTimeMock(Date mockTime){
this.mockTime = mockTime;
}
@Mock
public long currentTimeMillis(){
return mockTime.getTime();
}
}
これで、日付けも固定できてカバレッジも取得できてよかったよかった!
Author And Source
この問題について(JUnitでシステム日付けを固定する方法), 我々は、より多くの情報をここで見つけました https://qiita.com/watchmen-r/items/889515b33bc12655bcec著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .