Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking an enum using Mockito?

I need to mock the following enum:

public enum PersonStatus
{
    WORKING,
    HOLIDAY,
    SICK      
}

This is because it is used in the following class that I am testing:

Class under test:

public interface PersonRepository extends CrudRepository<Person, Integer>
{
    List<Person> findByStatus(PersonStatus personStatus);
}

Here is my current test attempt:

Current test:

public class PersonRepositoryTest {

    private final Logger LOGGER = LoggerFactory.getLogger(PersonRepositoryTest.class);

    //Mock the PersonRepository class
    @Mock
    private PersonRepository PersonRepository;

    @Mock
    private PersonStatus personStatus;

    @Before
    public void setUp() throws Exception {

        MockitoAnnotations.initMocks(this);
        assertThat(PersonRepository, notNullValue());
        assertThat(PersonStatus, notNullValue());
    }

    @Test
    public void testFindByStatus() throws ParseException {

        List<Person> personlist = PersonRepository.findByStatus(personStatus);
        assertThat(personlist, notNullValue());
    }
}

Which Gives following error:

error:

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class PersonStatus
Mockito cannot mock/spy following:
  - final classes
  - anonymous classes
  - primitive types

How can I solve this?

like image 653
java123999 Avatar asked May 05 '16 11:05

java123999


3 Answers

As already mentioned, using Mockito 2 and enabling experimental features.

What is actually missing, is an example snippet to demonstrate how. Considering an enum called LicenseHistoryAction with 4 already existing values, this will properly mock an UNSUPPORTED one:

try (MockedStatic<LicenseHistoryAction> licenseHistoryActionMockedStatic = Mockito.mockStatic(LicenseHistoryAction.class)) {
    final LicenseHistoryAction UNSUPPORTED = Mockito.mock(LicenseHistoryAction.class);
    Mockito.doReturn(4).when(UNSUPPORTED).ordinal();

    licenseHistoryActionMockedStatic.when(LicenseHistoryAction::values)
            .thenReturn(new LicenseHistoryAction[]{
                    LicenseHistoryAction.ASSIGN,
                    LicenseHistoryAction.RELEASE,
                    LicenseHistoryAction.UNBIND,
                    LicenseHistoryAction.DENY,
                    UNSUPPORTED});
}
like image 182
Mattia Moretta Avatar answered Sep 20 '22 14:09

Mattia Moretta


Just to complete the picture:

The latest version of Mockito 2 very well supports mocking of final classes. But you have to explicitly enable this new experimental feature first!

( see here on how to do that - it boils down to add a file mockito-extensions/org.mockito.plugins.MockMaker to your classpath, containing the value mock-maker-inline )

But of course: you only mock something if you have to. Your desire to mock Enum instances is most likely driven by either not understanding that - or because you created hard to test code here. In that sense the real answer would be to look into ways that avoid this kind of mocking in the first place.

like image 23
GhostCat Avatar answered Sep 17 '22 14:09

GhostCat


Your testFindByStatus is trying to assert that the findByStatus does not return null.

If the method works the same way regardless of the value of the personStatus param, just pass one of them:

@Test
public void testFindByStatus() throws ParseException {
    List<Person> personlist = PersonRepository.findByStatus(WORKING);
    assertThat(personlist, notNullValue());
}

If the behaviour may be different for the other possible values, you can test each of them:

@Test
public void testFindByStatus() throws ParseException {
    for (PersonStatus status : PersonStatus.values()) {
        List<Person> personlist = PersonRepository.findByStatus(status);
        assertThat(personlist, notNullValue());
    }
}
like image 36
assylias Avatar answered Sep 17 '22 14:09

assylias