Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a DateFormat class in junit test

I am trying to Mock a DateFormat class, since it has no purpose in the scope of my unit test. I am using the org.mockito.Mockito library.

Following code:

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");
    }
}

Gives following error:

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)

How do I mock the DateFormat class in a correct way?

like image 641
henrik Avatar asked Feb 05 '23 03:02

henrik


2 Answers

The problem is with implementation of format(Date date)

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

As you can see, it's final. Mockito cannot mock final methods. Instead, it will call the real method. As a workaround, you can mock method format(date, new StringBuffer(), DontCareFieldPosition.INSTANCE)

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

So when method format(date) will call your mocked method the result will be as you expected.

like image 146
Sergii Bishyr Avatar answered Feb 07 '23 18:02

Sergii Bishyr


As pointed out by Serghey Bishyr, you're trying to mock a final method, which can't be done in Mockito.

If your mocking framework doesn't allow you to do something (like mocking a final method), you either have to find an alternative framework (like Powermock), or work around it in another way.

From the 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).

None of the above points apply to your code, so there is no need to use a mock. And it's not "impractical or impossible" to use a real implementation of DateFormat.

Instead of supplying a mocked DateFormat, supply a SimpleDateFormat:

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

This will always return 2017-02-06 for any input, as apparently desired from the code in the question, since 's cause the text between them to be taken literally.

like image 41
Andy Turner Avatar answered Feb 07 '23 17:02

Andy Turner