JMockit издевается над System.currentTimeMillis ()

Запуск этого теста:

@Test
public void testSystemCurrentTimeMillis() {
    new NonStrictExpectations(System.class) {{
        System.currentTimeMillis(); result = 1438357206679L;
    }};
    long currentTime = System.currentTimeMillis();
    assertEquals(1438357206679L, currentTime);
}

Я получаю исключение IllegalStateException:

java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter
    at unittests.DateTest$1.(DateTest.java:24)
    at unittests.DateTest.testSystemCurrentTimeMillis(DateTest.java:23)

Что не так с моим тестом (JMockit 1.18)?


person trunkc    schedule 31.07.2015    source источник
comment
Каков результат? не могли бы вы поделиться кодом всего класса. И что такое NonStrictExpectations ??? Можете ли вы поделиться кодом и для этого.   -  person StackFlowed    schedule 31.07.2015
comment
NonStrictExpectations - это класс JMockit. Результат используется для насмешки JMockit. jmockit.org/tutorial/Mocking.html#expectation   -  person trunkc    schedule 31.07.2015
comment
Я всегда использую org.joda.time.DateTimeUtils для получения текущего времени DateTimeUtils.currentTimeMillis () и в модульном тесте DateTimeUtils.setCurrentMillisFixed (longValue) в конце DateTimeUtils.setCurrentMillisSystem ()   -  person StackFlowed    schedule 31.07.2015
comment
См. stackoverflow.com / questions / 17229525 /   -  person Raedwald    schedule 31.07.2015
comment
Я хочу сделать это с помощью JMockit.   -  person trunkc    schedule 31.07.2015
comment
Почему вы проверяете значение System.currentTimeMillis ()?   -  person forty-two    schedule 01.08.2015


Ответы (5)


Как и многие другие вещи с JMockit, это сделать достаточно просто. Попробуй это..

@Test
public void testSystemCurrentTimeMillis(@Mocked final System unused) {
    new NonStrictExpectations() {{
        System.currentTimeMillis(); result = 1438357206679L;
    }};
    long currentTime = System.currentTimeMillis();
    assertEquals(1438357206679L, currentTime);
}

Кстати, нашел этот сайт как отличный справочник. Вероятно, вас сбил статический метод. Все, что вам нужно сделать, это объявить класс со статическим методом как фиктивный - вам никогда не нужно ссылаться на переменную, поэтому я назвал его «неиспользуемым».

person unigeek    schedule 31.07.2015
comment
Принял ваш ответ, но я хотел высмеять только метод currentTimeMillis (), а не весь класс System. Кажется, это ошибка в JMockit. - person trunkc; 03.08.2015
comment
@trunkc Это не ошибка, а ограничение функции частичного имитации: она не может обрабатывать native такие методы, как System.currentTimeMillis(). Однако это ограничение распространяется только на Expectations API; вы можете имитировать только желаемый native метод, создав MockUp<System> (который использует Mockups API). - person Rogério; 03.08.2015
comment
Вы должны добавить намек об этом ограничении в учебник. - person trunkc; 04.08.2015

Мое последнее решение - создать MockUp для System, который только имитирует метод currentTimeMillis ():

private static class SystemMock extends MockUp<System> {
    @Mock
    public static long currentTimeMillis() {
        return 10000000L;
    }
}

@Test
public void testAddNowDate() {
    new SystemMock();
    long currentTime = System.currentTimeMillis();
    assertEquals(10000000L, currentTime);
}
person trunkc    schedule 03.08.2015
comment
Да, это лучшее решение в данном случае. Тем не менее, вы должны стараться по возможности избегать имитации системных часов; необходимость имитировать это в тесте намекает на проблему дизайна в тестируемом коде. - person Rogério; 03.08.2015
comment
@ Rogério хочет уточнить? Как я могу протестировать функциональность, зависящую от системных часов, не высмеивая их? - person KidCrippler; 11.01.2017
comment
Код, которому требуется текущее время, должен использовать тип более высокого уровня (java.util.Date, java.time.LocalDate и т. Д.), А не currentTimeMillis(). И затем он должен позволять передавать объекты даты / времени из клиентского кода, а не всегда получать текущее время. Если, конечно, вам действительно не нужно текущее время системных часов в милли / наносекундах. Как я уже сказал, звонок System.currentTimeMillis() вполне может быть проблемой дизайна, но я не могу знать наверняка без дополнительной информации. - person Rogério; 12.01.2017
comment
Ну, один из вариантов использования - это создать тестовый пример для проверки прошедшего времени с помощью currentTimeMillis или даже nanoTime. Если вы высмеиваете это, вы можете проверить наличие пограничных случаев. Я пробовал, но в моем случае это было слишком сложно ... слишком много ошибок OOM и т. Д. - person Jordan Gee; 16.08.2019
comment
Да! Все в Интернете говорит о проблеме дизайна при издевательстве над Системой, но это все равно, что сказать, что мы никогда не должны использовать Систему, что не соответствует действительности. Иногда возникает проблема с дизайном. Иногда вы ничего не можете сделать, чтобы изменить указанный дизайн. Иногда вам просто нужна помощь, чтобы смоделировать Систему, независимо от дизайна. - person John Mercier; 23.04.2020

Эта вещь была введена в JMockit версии 1.17 только для использования ссылки на объект с вашим блоком NonStrictExpectation () {}, значение атрибута Deprecated для Mocked

Устарел атрибут "value" @Mocked, который используется для "статического" частичного имитации. Существующие варианты использования следует заменить на «динамический» частичный имитатор, передав экземпляр или класс для частичного имитации в вызове конструктора Expectations (Object ...) или применив класс MockUp.

См. Ссылку ниже: История версий JMockit

person Amruta Mistry    schedule 02.08.2015
comment
Я не использую атрибут value @Mocked. - person trunkc; 03.08.2015

Ага, это частичное издевательство. С небольшими исправлениями в nonStrictExpectation () {} ваш вышеупомянутый код также может получить исправление:

@Mocked
private System system;

new NonStrictExpectations() {{
    System.currentTimeMillis(); 
    result = 1438357206679L;
}};

long currentTime = System.currentTimeMillis();
assertEquals(1438357206679L, currentTime);

Это тоже должно сработать.

person Amruta Mistry    schedule 03.08.2015
comment
В этом примере не используется частичное издевательство. - person John Mercier; 05.03.2019

Для этого я использую PowerMock:

private void configureSystemClockMock(final int clockJump) {
    AtomicInteger callCount = new AtomicInteger();

    Answer<Integer> answer = invocation -> {
        callCount.addAndGet(1);
        return callCount.get() * clockJump;
    };

    PowerMockito.mockStatic(System.class);
    PowerMockito.doAnswer(answer).when(System.class);
    System.currentTimeMillis();
}

Конечно, вы вкладываете в заклинание все, что хотите.

person Zangdar    schedule 11.08.2020