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

前端 未结 3 672
时光说笑
时光说笑 2021-01-15 09:05

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

public class FilterDataController {

    public static final String DATE_FORMAT = \"y         


        
相关标签:
3条回答
  • 2021-01-15 09:32

    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));
        }
    }
    
    0 讨论(0)
  • 2021-01-15 09:34

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-15 09:46

    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.
    0 讨论(0)
提交回复
热议问题