[英]How to mock the default constructor of the Date class with JMockit?
I want to mock the default constructor of java.util.date
so it does not construct a Date
object representing the time when it was created, but always the same Date
object (in my example below 31 Dec 2010).我想模拟
java.util.date
的默认构造函数,因此它不会构造表示创建时间的Date
对象,但始终是相同的Date
对象(在我的示例中为 2010 年 12 月 31 日)。 I tried doing this with JMockit
and JUnit
, but when executing my test below, the output is always Thu Jan 01 01:00:00 CET 1970
.我尝试使用
JMockit
和JUnit
执行此操作,但是在执行下面的测试时,输出始终为Thu Jan 01 01:00:00 CET 1970
。 So what is wrong with my mock of Date()
?那么我对
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's answer was a good hint for me. al nik 的回答对我来说是一个很好的提示。 It is better to mock the
System
class instead of the Date
class to generate a fake time.最好模拟
System
类而不是Date
类来生成假时间。 My own solution in the end was simply to mock the System.currentTimeMillis()
method (this method is called by Date()
internally).最后我自己的解决方案只是模拟
System.currentTimeMillis()
方法(此方法由Date()
内部调用)。
JMockit 1.5 and later 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 and earlier 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();
}
}
As suggested in the Test Driven book it's good practice to use a SystemTime abstraction in your java classes.正如Test Driven书中所建议的,在您的 java 类中使用 SystemTime 抽象是一种很好的做法。 Replace your method calls (System#currentTimeMillis and Calendar#getInstance) and direct construction (new Date()) with static method calls like:
将您的方法调用(System#currentTimeMillis 和 Calendar#getInstance)和直接构造(new Date())替换为静态方法调用,例如:
long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();
To fake the time you just need to modify what's returned by your SystemTime class.要伪造时间,您只需要修改 SystemTime 类返回的内容。
SystemTime use a TimeSource interface that by default delegates to System.currentTimeMillis() SystemTime 使用默认委托给 System.currentTimeMillis() 的 TimeSource 接口
public interface TimeSource {
long millis();
}
a configurable SystemTime implementation could be something like this一个可配置的 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);
}
}
and to fake the returned time you simply do并伪造返回的时间,您只需这样做
@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 library simplifies working with dates in Java and offers you something like this out of the box Joda-Time 库简化了 Java 中日期的处理,并为您提供开箱即用的功能
You mocked the constructor, and inside you made an instance of Date (that has nothing to do with the one constructed) and just threw it away.您模拟了构造函数,并在内部创建了一个 Date 实例(与构造的实例无关),然后将其扔掉。 Since the default constructor is mocked out, date is not initialized to the current time, and so you get the time of zero (which represents 1970-01-01).
由于默认构造函数被模拟出来,日期未初始化为当前时间,因此您将获得零时间(代表 1970-01-01)。
To modify the returned date you need to use a magic "it" attribute, like so:要修改返回的日期,您需要使用一个神奇的“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!
}
}
And here's a complete JUnit example based on @asmaier's great answer:这是一个基于@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
}
When using Maven, configure JMockit as follows in pom.xml
:使用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.