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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 06:58:56  来源:igfitidea点击:

How to mock the default constructor of the Date class with JMockit?

javadefault-constructorjmockit

提问by asmaier

I want to mock the default constructor of java.util.dateso it does not construct a Dateobject representing the time when it was created, but always the same Dateobject (in my example below 31 Dec 2010). I tried doing this with JMockitand 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 日下面的示例中)。我尝试使用JMockitand执行此操作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 Systemclass instead of the Dateclass 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!
    }
}