### How do I use MockitoAnnotations and @Captor?

406
views
0
19 months ago by

Does the @Captor annotation make life any simpler when setting up captors in unit tests?

0
19 months ago by

MockitoAnnotations allow you to declare all your captors at the head of your test class, then just use them where needed rather than declaring/initialising them each time. They also permit you to setup a captor for a generic item such as a list, where the traditional approach doesn't work because there are no separate classes for generics.

Using DefaultBookingCommandServiceTest as an example, under all the variable declarations is a set of captor definitions:

    @Captor
private ArgumentCaptor<String> stringCaptor;
@Captor
private ArgumentCaptor<BigDecimal> bigDecimalCaptor;
@Captor
private ArgumentCaptor<List<String>> listOfStringCaptor;
@Captor
private ArgumentCaptor<TypedMessage> typedMessageCaptor;



These just declare the captor types; the neat part is that they are all initialised together using a single command:

    MockitoAnnotations.initMocks(this);

which is placed in setup(). Now all that's needed in the actual test is

    verify(bookingService).switchBookingBookerToOrgOwner(stringCaptor.capture(), eq(userId.toString()));
assertEquals(bookingQm.getId(), stringCaptor.getValue());

We might consider creating an abstract parent class along the lines of

public class AbstractUnitTest {

@Captor
protected ArgumentCaptor<String> stringCaptor;
@Captor
protected ArgumentCaptor<BigDecimal> bigDecimalCaptor;
@Captor
protected ArgumentCaptor<List<String>> listOfStringCaptor;
@Captor
protected ArgumentCaptor<TypedMessage> typedMessageCaptor;

protected void setup() {
MockitoAnnotations.initMocks(this);
}
}

and putting all the captor definitions we'll ever need into it. Then each unit test can be reparented onto this class and the first line of its setup() method will read

    super.setup();

It's likely that a parent class of this type would gradually fill up with useful methods, avoiding a certain amount of repetition.

0
16 months ago by

Don't use

MockitoAnnotations.initMocks(this);

Any occurrences of the above should be replaced with either

@RunWith(PowerMockRunner.class)

or

@RunWith(MockitoJUnitRunner.class)

as both will reset the mocks in between tests and they do not mess up the mock implementations if the additional features of PowerMock are required.