Sarah Guarino
Sarah Guarino

Reputation: 194

Running Tests with MockitoJUnitRunner fails verify asserts

Is there a way to mock a Repository without the @RunWith(MockitoJUnitRunner) annotation on the class?

I have a test that passed without the annotation but fails with it. Without it, my repo test doesn't work. It's a catch 22.

When I use that annotation, my when() methods in my tests no longer stub behavior, mocks do nothing, and despite setting break ppoints and those breakpoints being hit (indicating the line/method is run), verify(..., times(x)) statements say the mocked object never interacted with that method. I've been pulling my hair out on why using the @RunWith(MockitoJUnitRunner) annotation would make the most simple parts of Mockito not work.

I can't find any threads asking about this but maybe someone knows better keywords to use. Does this sound like a known issue?

Here is my test:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;

// toggling this below annotation is the source of grief.
//@RunWith(MockitoJUnitRunner.class)
public class LoadEditEntityChangeLogServiceImplTest {

    @InjectMocks
    private ServiceImpl serviceMock;

    @Mock
    private EditStepRepository editStepRepository;

    @Mock
    private EditMapper editMapper;

    @Before
    public void init() {
        initMocks(this);
    }


    @Test // when the RunWith is commented out, this passes. When it is not, the test fails the verify assert. 
    public void mapEditEntityFromAction_Test() {
        EditDTO editDTO = Mockito.mock(EditDTO.class);
        when(editDTO.getSysNum()).thenReturn((long)7334);

        EditEntity editEntity = new editEntity();
        editEntity.setSysNum(editDTO.getSysNum());

        when(editMapper.mapToEntity(eq(editDTO))).thenReturn(editEntity);

        editEntity response = serviceMock.mapEditEntityFromAction(editDTO);

        verify(loadEditMapper, times(1)).mapToEntity(eq(loadEventDTO));
        assertEquals(loadEventDTO.getSystemNumber(), response.getSystemNumber());
    }

    @Test // this will fail without the @RunWith as the mocked repo will be null and throws NullPointerException when used.
    public void updateConvertedEventSegment_Test() {
        EditEntity editEntity = new EditEntity();
        EditStepEntity editStepEntity = new EditStepEntity();
        editEntity.setEditStep(editStepEntity);

        doReturn(editStepEntity).when(editStepRepository).save(any());

        serviceMock.updateEditStep(editEntity);

        verify(editEntity, times(1)).getEditStep();
        verify(editStepRepository, times(1)).save(eq(editStepEntity));
    }
}

Upvotes: 0

Views: 1474

Answers (1)

Mark Bramnik
Mark Bramnik

Reputation: 42441

You should understand what does this runner actually do:

Basically it allows injecting mocks (prepared by mockito with Mockito.mock(...) ) into the test fields annotated with @Mock. In the question, since you've commented out the runner, all these fields will be null.

When you annotated something with @InjectMocks - it will inject the mocks into the fields of the object of type of the annotated reference.

One more point to clarify here: MockitoAnnotations.initMocks(this) will do the same as the "runner" so no need to include both (you should use initMocks if you can't use the runner for some reason, like if there is already another runner that must be used)

Now, you ask:

Is there a way to mock a Repository without the @RunWith(MockitoJUnitRunner) annotation on the class?

The answer is - yes, you can, in fact you don't have to use the runner, sometimes its more convenient.

So, assuming you really use this runner, the real question is what exactly do you mean by "my repository doesn't work". Does this mean that there exists a reference in the service that points of this repository and its null?

Does it mean that there is a mock of repository but when you execute the call "under the test" the mock is different?

You don't show it in the code, but I assume you have some like this:

public class ServiceImpl {
   private final EditStepRepository editStepRepository;

   public ServiceImpl(EditStepRepository editStepRepository) {
      this.editStepRepository = editStepRepository;
   }
   ...
}

But if so, once you create a mock (and indeed there should be a mock injected into the ServiceImpl class (check this out with debugger or something), There should be expectatations specified on the repository, usually there should be code like this in the test:

Mockito.when(editStepRepository.doSomething(...)).thenReturn(...)

You haven't placed any of these lines, that why it doesn't work.

But all-in-all since the question contains many uncertain technicalities like this, I can't tell more than that other that speculating...

Upvotes: 1

Related Questions