[英]How to mock the default constructor of the Date class with JMockit?
我想模擬java.util.date
的默認構造函數,因此它不會構造表示創建時間的Date
對象,但始終是相同的Date
對象(在我的示例中為 2010 年 12 月 31 日)。 我嘗試使用JMockit
和JUnit
執行此操作,但是在執行下面的測試時,輸出始終為Thu Jan 01 01:00:00 CET 1970
。 那么我對Date()
模擬有什么問題?
import java.util.Date;
import org.junit.*;
import mockit.*;
public class AppTest {
@Before
public void setUp() {
Mockit.setUpMocks(MockedDate.class);
}
@After
public void tearDown() {
Mockit.tearDownMocks();
}
@Test
public void testDate() {
Date today=new Date();
System.out.println(today.toString());
}
@MockClass(realClass=Date.class)
public static class MockedDate {
@Mock
public void $init() {
// Now should be always 31.12.2010!
new Date(110,11,31); //110 = 2010! 11 = December! This is sick!
}
}
}
al nik 的回答對我來說是一個很好的提示。 最好模擬System
類而不是Date
類來生成假時間。 最后我自己的解決方案只是模擬System.currentTimeMillis()
方法(此方法由Date()
內部調用)。
JMockit 1.5 及更高版本
new MockUp<System>(){
@Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
};
JMockit 1.4 及更早版本
@MockClass(realClass = System.class)
public static class MockedSystem {
@Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
}
正如Test Driven書中所建議的,在您的 java 類中使用 SystemTime 抽象是一種很好的做法。 將您的方法調用(System#currentTimeMillis 和 Calendar#getInstance)和直接構造(new Date())替換為靜態方法調用,例如:
long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();
要偽造時間,您只需要修改 SystemTime 類返回的內容。
SystemTime 使用默認委托給 System.currentTimeMillis() 的 TimeSource 接口
public interface TimeSource {
long millis();
}
一個可配置的 SystemTime 實現可能是這樣的
public class SystemTime {
private static final TimeSource defaultSrc =
new TimeSource() {
public long millis() {
return System.currentTimeMillis();
}
};
private static TimeSource source = null;
public static long asMillis() {
return getTimeSource().millis();
}
public static Date asDate() {
return new Date(asMillis());
}
public static void reset() {
setTimeSource(null);
}
public static void setTimeSource(TimeSource source) {
SystemTime.source = source;
}
private static TimeSource getTimeSource() {
return (source != null ? source : defaultSrc);
}
}
並偽造返回的時間,您只需這樣做
@Test
public void clockReturnsFakedTimeInMilliseconds() throws Exception {
final long fakeTime = 123456790L;
SystemTime.setTimeSource(new TimeSource() {
public long millis() {
return fakeTime;
}
});
long clock = SystemTime.asMillis();
assertEquals("Should return fake time", fakeTime, clock);
}
Joda-Time 庫簡化了 Java 中日期的處理,並為您提供開箱即用的功能
您模擬了構造函數,並在內部創建了一個 Date 實例(與構造的實例無關),然后將其扔掉。 由於默認構造函數被模擬出來,日期未初始化為當前時間,因此您將獲得零時間(代表 1970-01-01)。
要修改返回的日期,您需要使用一個神奇的“it”屬性,如下所示:
@MockClass(realClass=Date.class)
public static class MockedDate {
public Date it;
@Mock
public void $init() {
// This is sick!
it.setDate(31);
it.setYear(110); // 110 = 2010!
it.setMonth(11); // 11 = December!
}
}
這是一個基於@asmaier 的精彩回答的完整 JUnit 示例:
@Test
public void dateConstructorReturnsMockedDate() throws ParseException {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
final Date mockDate = dateFormat.parse("2002-02-02");
new MockUp<System>(){
@Mock
public long currentTimeMillis() {
return mockDate.getTime();
}
};
final Date actualDate = new Date();
assertThat(actualDate).isEqualTo(mockDate); // using AssertJ
}
使用Maven時,在pom.xml
配置JMockit如下:
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>
-javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
</argLine>
<disableXmlReport>true</disableXmlReport>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jmockit.version>1.44</jmockit.version>
</properties>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.