When I enter the unit test phase at work, I often want to fix the date. This time I tried to fix the time using the Mock library.
This time I will write a JUnit to test the following.
public class OutputDate {
public void getDate(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy year MM month dd day hh hour mm minute ss second SSS millisecond");
System.out.println(sdf.format(new Date()));
}
}
If all goes well, the date and time output by new Date () should be fixed!
I learned from my boss that it can be achieved by the following methods.
@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();
}
/**
*Fix system date
*This method cannot fix up to milliseconds
*/
private static void setDatemock(){
Calendar cal = Calendar.getInstance();
//Set the time to 10:10:10 on January 1, 2018(Month is 0 in January)
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();
}
}
This is a method of trying to fix using the set () method of the Calendar class with the setDatemock () method. At first I thought this was fine, but ** I can't fix the milliseconds with this. ** Because there is nothing to specify up to milliseconds in the set method (in the range I searched for).
I was wondering what to do, but I wonder if I can do it well with strings? Based on the hint from my boss, I came up with the following method.
@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();
}
/**
*Fix system date
*This method fixes up to milliseconds
*/
private static void setDatemock() {
String strDate = "2018-01-01 10:10:10.111";
//Set the time to 10:10:10 on January 1, 2018(Month is 0 in January)
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();
}
}
This is a method to forcibly convert the date and time you want to fix from a character string to Date format. In this way, we were able to fix milliseconds. Congratulations ...
I was completely relieved by the above method, but I had a problem when I got the coverage. It seems that the tool "Eclemma" used when acquiring coverage in Eclipse does not work well when PowerMockRunner.class is specified in the test runner. It seems to be a known problem, and it seems that it can be solved by using @Rule as shown below.
Click here for how to get coverage with Eclemma using PowerMock → https://code.i-harness.com/ja/q/1647e8c
However, at the time of the unit test, I was eager to find another way. Then I came up with the following method using the JMockit library.
@RunWith(JMockit.class)
public class FixSysDateUsingJMockit {
//You have to add 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 mock class
*/
public static class CurrentTimeMock extends MockUp<System>{
Date mockTime;
public CurrentTimeMock(Date mockTime){
this.mockTime = mockTime;
}
@Mock
public long currentTimeMillis(){
return mockTime.getTime();
}
}
I'm glad I was able to fix the date and get coverage!
Recommended Posts