简体   繁体   中英

How to check if-statement in method using Mockito and JUnit?

I have method that I should test. Code (of course some parts were cut):

public class FilterDataController {

    public static final String DATE_FORMAT = "yyyy-MM-dd";

    @Autowired
    private FilterDataProvider filterDataProvider;

    @ApiOperation(value = "Get possible filter data",response = ResponseEntity.class)
    @ApiResponses(value = {
            @ApiResponse(...),
            @ApiResponse(...)})
    @RequestMapping(path = "...", method = RequestMethod.GET)
    public ResponseEntity<Object> getPossibleFilterData(
            @RequestParam(value = "startDate") @DateTimeFormat(pattern=DATE_FORMAT) final Date startDate,
            @RequestParam(value = "endDate") @DateTimeFormat(pattern=DATE_FORMAT) final Date endDate) {
        if (endDate.compareTo(startDate) == -1){
            throw new ValueNotAllowedException("End date should be after or equal start date");
        }
        else {
            Date newEndDate = endDate;
            if (startDate.equals(endDate)){
                newEndDate = new Date(endDate.getTime() + TimeUnit.DAYS.toMillis(1) - 1);
            }

            List<String> possibleCountries = Lists.newArrayList(filterDataProvider.getPossibleCountries(startDate, newEndDate));

            return new ResponseEntity<>(new FilterResponse(possibleCountries),HttpStatus.OK);
        }
    }   
}

Question: how to check if-statement in method getPossibleFilterData using Mockito and JUnit? I want pass equal dates to method then check that my if-statement works properly.

If you really want a pure unit test not an integration test, you could rely on the annotation @Mock to mock your service FilterDataProvider and @InjectMocks to inject your mock into your instance of FilterDataController .

Then you could propose 3 tests:

  1. One test where the dates are corrects but different,
  2. Another one where the dates are corrects but equal
  3. And the last one where the dates are incorrect which will thrown a ValueNotAllowedException that could be tested out of the box using @Test(expected = ValueNotAllowedException.class) .

If you need to make sure that filterDataProvider.getPossibleCountries(startDate, newEndDate) has been called with the expected arguments you need to use verify .

The code would then be something like that:

@RunWith(MockitoJUnitRunner.class)
public class FilterDataControllerTest {
    @Mock
    FilterDataProvider filterDataProvider;
    @InjectMocks
    FilterDataController controller;

    @Test(expected = ValueNotAllowedException.class)
    public void testGetPossibleFilterDataIncorrectDates() {
        controller.getPossibleFilterData(new Date(1L), new Date(0L));
    }

    @Test
    public void testGetPossibleFilterDataCorrectDates() {
        // Make the mock returns a list of fake possibilities
        Mockito.when(
            filterDataProvider.getPossibleCountries(
                Mockito.anyObject(), Mockito.anyObject()
            )
        ).thenReturn(Arrays.asList("foo", "bar"));
        ResponseEntity<Object> response = controller.getPossibleFilterData(
            new Date(0L), new Date(1L)
        );
        Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
        // Make sure that 
        // filterDataProvider.getPossibleCountries(new Date(0L), new Date(1L))
        // has been called as expected
        Mockito.verify(filterDataProvider).getPossibleCountries(
            new Date(0L), new Date(1L)
        );
        // Test response.getBody() here
    }

    @Test
    public void testGetPossibleFilterDataEqualDates() {
        // Make the mock returns a list of fake possibilities
        Mockito.when(
            filterDataProvider.getPossibleCountries(
                Mockito.anyObject(), Mockito.anyObject()
            )
        ).thenReturn(Arrays.asList("foo", "bar"));
        // Call the controller with the same dates
        ResponseEntity<Object> response = controller.getPossibleFilterData(
            new Date(1L), new Date(1L)
        );
        Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
        Mockito.verify(filterDataProvider).getPossibleCountries(
            new Date(1L), new Date(TimeUnit.DAYS.toMillis(1))
        );
        // Test response.getBody() here
    }
}

You will have to mock FilterDataProvider and then inject this into your test class using InjectMocks.

getPossibleFilterData will be the method under test, so choose any specific date (use Calendar.set(...) , then Calendar.getTime() ) and send this same date as both the startDate and endDate.

Now after getPossibleFilterData is completed, you can verify whether filterDataProvider.getPossibleCountries was called with a end Date that is one millisecond more than the start date. This can be done through Calendar.getTimeInMillis() inside the mocked class's method, or by verifying with Mockito with a Date that is one millisecond more than the date that was originally specified.

Edit: Code example provided:

public class FilterDataControllerTest {
    @Test
    public void testSameDate() {
        FilterDataProvider provider = Mockito.mock(FilterDataProvider.class);
        FilterDataController controller = new FilterDataController(provider);

        Date startDate = new GregorianCalendar(2016, Calendar.JANUARY, 11).getTime();
        Date endDate = new GregorianCalendar(2016, Calendar.JANUARY, 11).getTime();
        Date expectedEndDate = new Date(endDate.getTime() + TimeUnit.DAYS.toMillis(1) - 1);

        controller.getPossibleFilterData(startDate, endDate);

        Mockito.verify(provider).getPossibleCountries(Mockito.eq(startDate), Mockito.eq(expectedEndDate));
    }
}

I see two main approaches.

  1. Using Mockito functionality: if you inject your controller with a mock FilterDataProvider (which is the standard approach, using for example MockitoJUnitRunner and @InjectMocks) , then you can use Mockito's "verity" option to make sure it got the correct endDate. See discussion: http://www.vogella.com/tutorials/Mockito/article.html#mockito_verify
  2. Obviously, there are other approaches that rely on logic rather than technicalities. For example: refactoring the "if" part to a separateMethod "correctEndDate", or populating your data so that a different list of coutries is returned based on the endDate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM