Mocking a DateFormat class in junit test

10,135

Solution 1

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.

Solution 2

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.

Share:
10,135
henrik
Author by

henrik

Software developer @ Pixney web agency, Sweden. 10+ years of work experience in developing PHP and Java apps. www.pixney.com

Updated on June 08, 2022

Comments

  • henrik
    henrik almost 2 years

    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?