Home > OS >  Testing Spring Controller with Mockito
Testing Spring Controller with Mockito

Time:12-16

I am trying to learn to test using Spring 5, Mockito, and JUnit 5. I have a small normal controller class and its test is as below:

@Controller
@RequestMapping("/customer")
public class CustomerController {
    @Autowired
    CustomerService customerService;
    
    @Autowired
    CustomerForm customerForm;

    @GetMapping("/index")
    public ModelAndView index(){
        String customerName = customerService.getCustomerById(14).getFirstname();  <-- Giving me error here
        customerForm.setCustomerName(customerName);

        ModelAndView modelAndView = new ModelAndView("customer/pages/customer/Home");
        modelAndView.addObject("customerForm", customerForm);
        return modelAndView;
    }
}
@ExtendWith(MockitoExtension.class)
class CustomerControllerTest {
    
    @InjectMocks
    CustomerController customerController;
    
    @Mock
    CustomerServiceImpl customerService;
    
    @Mock
    CustomerForm customerForm;
    
    Customer customer;
    String customerName;
    
    @SuppressWarnings("deprecation")
    @BeforeEach
    void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        customer = new Customer(14, "John");        
        customerName = "John";
    }

    @Test
    void testIndex() {
        int customerId = 14;
        when(customerService.getCustomerById(customerId).getFirstname()).thenReturn(customerName);  <-- Giving me error here, NullPointerException
        customerForm.setCustomerName(customerName);
        
        ModelAndView mav = customerController.index();
        assertEquals( customerForm, mav.getModel().get("customerForm"));
    }
}

Error:

java.lang.NullPointerException
    at com.primis.controller.CustomerControllerTest.testIndex(CustomerControllerTest.java:66)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)

When I run this test, I am getting NullPointerException as shown. Please can someone point me in the right direction, what I am doing wrong.

Thank you

CodePudding user response:

You have to mock customerService.getCustomerById(customerId) first, otherwise it will return null and, in this case, throw NPE.

CodePudding user response:

You are mocking the wrong thing:

when(customerService.getCustomerById(customerId).getFirstname()).thenReturn(customerName);

What you actually need to mock is only the call customerService.getCustomerById(). This means that your testing code should be something like:

@ExtendWith(MockitoExtension.class)
class CustomerControllerTest {
    
    @InjectMocks
    CustomerController customerController;
    
    @Mock
    CustomerServiceImpl customerService;
    
    @Mock
    CustomerForm customerForm;
    
    Customer customer;
    String customerName;
    
    @SuppressWarnings("deprecation")
    @BeforeEach
    void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        customer = new Customer(14, "John");        
        customerName = "John";
    }

    @Test
    void testIndex() {
        int customerId = 14;
        when(customerService.getCustomerById(customerId)).thenReturn(customer);
        customerForm.setCustomerName(customerName);
        
        ModelAndView mav = customerController.index();
        assertEquals( customerForm, mav.getModel().get("customerForm"));
    }
}

As a side note, I believe that with @ExtendWith(MockitoExtension.class) you don't really need the explicit MockitoAnnotations.initMocks(this); call.

  • Related