2017-02-06 27 views
2

Я пытаюсь выполнить Mock класс DateFormat, поскольку он не имеет никакой цели в рамках моего модульного теста. Я использую библиотеку org.mockito.Mockito.Отказывание класса DateFormat в junit-тесте

следующий код:

import static org.mockito.Mockito.when; 
import static org.mockito.Mockito.any; 
import org.mockito.Mock; 
import org.mockito.MockitoAnnotations; 

import org.junit.Before; 

public class someTest { 

    @Mock 
    DateFormat formatter; 

    @Before 
    public void before() { 
     MockitoAnnotations.initMocks(this); 
     when(formatter.format(any(Date.class))).thenReturn("2017-02-06"); 
    } 
} 

Выдает следующее сообщение об ошибке:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 3 matchers expected, 1 recorded:

-> at someTest.before(someTest.java:33)

This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

at java.text.DateFormat.format(Unknown Source)
at someTest.before(someTest.java:33)

Как издеваться класс DateFormat в правильном пути?

+0

Не так ли просто создать реальный экземпляр? 'formatter = new SimpleDateFormat (" '2017-02-06' ");' –

+0

@AndyTurner В чем преимущество использования реального экземпляра по сравнению с объектом Mocked? – henrik

+1

Я расскажу вам об этом: как вы думаете, что вы получаете, издеваясь над этим объектом, а не используя реальный экземпляр? –

ответ

4

Проблема с осуществлением format(Date date)

public final String format(Date date) { 
    return format(date, new StringBuffer(), 
        DontCareFieldPosition.INSTANCE).toString(); 
} 

Как вы можете видеть, это финал. Мокито не может высмеять окончательные методы. Вместо этого он вызовет реальный метод. В качестве обходного пути, вы можете издеваться методу format(date, new StringBuffer(), DontCareFieldPosition.INSTANCE)

when(formatter.format(any(Date.class), any(StringBuffer.class), 
         any(FieldPosition.class))) 
    .thenReturn(new StringBuffer("2017-02-06")); 

Так что, когда метод format(date) будет вызывать ваш издевались метод результат будет, как вы ожидали.

+0

Благодарим вас за указание причины ошибки. Сообщение об ошибке, предоставленное инфраструктурой, было немного запутанным. Ваше обеспеченное обходное решение в порядке со мной! – henrik

+1

Небольшая деталь, которая отсутствует здесь (или, возможно, недостаточно ясно), заключается в том, что вызов 'when' вызывает реальный метод, который вызывает метод делегата, поэтому первый, что mockito знает о вызове' when', что метод делегата вызывается, поэтому вам нужно настроить метод mock для вызова метода * this *. Это означает, что ваш тестовый код зависит от деталей реализации «TextFormat» - поэтому это делает тестовый код хрупким, как следствие проблемы [Fragile Base Class] (https://en.m.wikipedia.org/wiki/ Fragile_base_class). –

+0

@AndyTurner Вы имеете в виду DateFormat, а не TextFormat, правильно? В противном случае я смущен :) Да, вы правы, изменения в структуре mockit могут привести к тому, что тест перестанет работать, но это плавники со мной. Обновление тестов легко управляется по сравнению с производственным кодом. Хороший момент, хотя! – henrik

2

Как указано Serghey Bishyr, вы пытаетесь высмеять final method, что невозможно сделать в Mockito.

Если ваш издевательский фреймворк не позволяет вам что-либо делать (например, высмеивать окончательный метод), вам нужно либо найти альтернативную структуру (например, Powermock), либо обойти ее по-другому.

Из Wikipedia article about mocks:

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when a real object is impractical or impossible to incorporate into a unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place:

  • the object supplies non-deterministic results (e.g. the current time or the current temperature);
  • it has states that are difficult to create or reproduce (e.g. a network error);
  • it is slow (e.g. a complete database, which would have to be initialized before the test);
  • it does not yet exist or may change behavior;
  • it would have to include information and methods exclusively for testing purposes (and not for its actual task).

Ни один из вышеперечисленных пунктов не применяются к коду, поэтому нет необходимости использовать издеваться. И нецелесообразно или невозможно использовать реальную реализацию DateFormat.

Вместо подачи издевались DateFormat, подводимой к SimpleDateFormat:

formatter = new SimpleDateFormat("'2017-02-06'"); 

Это всегда будет возвращать 2017-02-06 для любого входа, как, видимо желаемому из кода в вопросе, так как ' s привести текст между ними восприниматься буквально.

+0

Предоставление вам +1 для обеспечения обходного пути! – henrik

0

За правильные ответы, один важное замечание:

when(formatter.format(any(Date.class)) 

Если метод не будет окончательным, вы можете просто пойти с

when(formatter.format(any()) 

Mockito достаточно умен, чтобы понять, что происходит и (по крайней мере, при использовании Java8)

 Смежные вопросы

  • Нет связанных вопросов^_^