Как смоделировать конструктор по умолчанию класса Date с JMockit? - PullRequest
3 голосов
/ 30 декабря 2010

Я хочу смоделировать конструктор по умолчанию java.util.date, чтобы он не создавал объект Date, представляющий время, когда он был создан, но всегда один и тот же объект Date (в моем примере ниже 31 декабря 2010 г.).Я пытался сделать это с 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!
        }
    }
}

Ответы [ 3 ]

10 голосов
/ 31 декабря 2010

Ответ Аль Ника был хорошим намеком на меня.Лучше издеваться над классом 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();
    }
}
9 голосов
/ 30 декабря 2010

Как предлагается в книге Test Driven , хорошей практикой является использование абстракции SystemTime в ваших классах Java.Замените ваши вызовы методов (System # currentTimeMillis и Calendar # getInstance) и прямое построение (new Date ()) статическими вызовами методов, такими как:

long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();

Чтобы подделать время, вам просто нужно изменить то, что возвращает вашКласс SystemTime.
SystemTime использует интерфейс TimeSource, который по умолчанию делегирует System.currentTimeMillis ()

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 и предлагает вам что-то подобное из коробки

0 голосов
/ 30 декабря 2010

Вы издевались над конструктором, и внутри вы сделали экземпляр Date (который не имеет ничего общего с созданным) и просто выбросили его.Поскольку конструктор по умолчанию является макетом, дата не инициализируется текущим временем, и поэтому вы получаете нулевое время (которое представляет 1970-01-01).

Чтобы изменить возвращенную дату, вам нужно использоватьмагический атрибут "это", например:

@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!
    }
}
...