java 如何使用 JMockit 模拟 Date 类的默认构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4563584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to mock the default constructor of the Date class with JMockit?
提问by asmaier
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). 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
. So what is wrong with my mock of Date()
?
我想模拟它的默认构造函数,java.util.date
因此它不会构造一个Date
表示它创建时间的对象,而是始终是同一个Date
对象(在我 2010 年 12 月 31 日下面的示例中)。我尝试使用JMockit
and执行此操作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!
}
}
}
回答by asmaier
al nik's answer was a good hint for me. It is better to mock the System
class instead of the Date
class to generate a fake time. My own solution in the end was simply to mock the System.currentTimeMillis()
method (this method is called by Date()
internally).
al nik 的回答对我来说是一个很好的提示。最好模拟System
类而不是Date
类来生成假时间。最后我自己的解决方案只是模拟该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();
}
}
回答by mickthompson
As suggested in the Test Drivenbook it's good practice to use a SystemTime abstraction in your java classes. Replace your method calls (System#currentTimeMillis and Calendar#getInstance) and direct construction (new Date()) with static method calls like:
正如Test Driven书中所建议的,在您的 java 类中使用 SystemTime 抽象是一种很好的做法。将您的方法调用(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 use a TimeSource interface that by default delegates to System.currentTimeMillis()
要伪造时间,您只需要修改 SystemTime 类返回的内容。
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 librarysimplifies working with dates in Java and offers you something like this out of the box
Joda-Time 库简化了 Java 中日期的处理,并为您提供开箱即用的功能
回答by fdreger
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. 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).
您模拟了构造函数,并在内部创建了一个 Date 实例(与构造的实例无关),然后将其扔掉。由于默认构造函数被模拟出来,日期未初始化为当前时间,因此您将获得零时间(代表 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!
}
}