My controller code is not reachable from the MockMvc get request and i am always getting 404

940 views Asked by At

I am trying to mock my controller and write testcases for it. But when I tried to debug the Test class the control is not getting into my Controller class. I am not sure what I am doing wrong here.

Please help me to resolve this as I am stuck on this for almost more that 3 hours.

My Service class


import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bnpp.leavemanagement.dao.DepartmentRepository;
import com.bnpp.leavemanagement.model.DepartmentModel;

@Service
public class DepartmentService 
{
    @Autowired
    DepartmentRepository depRepo;
    
    public List<DepartmentModel> listDepartment = new ArrayList<>();
    
    public List<DepartmentModel> getAllDepartments()
    {
        List<DepartmentModel> allDepartment = depRepo.findAll();
        return allDepartment;
    }
    
    public DepartmentModel fetchDepartmentById( int id)
    {
        DepartmentModel depDetail = null;
        try
        {
            depDetail = depRepo.findById(Long.valueOf(id)).get();
        }
        catch(Exception ex)
        {
            depDetail = null;
        }
        return depDetail;
    }
    
    public DepartmentModel addDepartment(DepartmentModel depDetail)
    {
        DepartmentModel depExists = null;
        if (listDepartment.size() > 0) 
        {
            depExists = listDepartment.stream()
                    .filter(d -> d.getName().equalsIgnoreCase(depDetail.getName()))
                    .findFirst()
                    .orElse(null);
        }
        
        //Below condition is to restrict duplicate department creation
        if(depExists == null)
        {
            depRepo.save(depDetail);
            listDepartment.add(depDetail);
        }
        else
        {
            return null;
        }
        
        return depDetail;
    }
    
    public DepartmentModel updateDepartment(DepartmentModel depDetail)
    {
        DepartmentModel depUpdate = null;
        try
        {
            depUpdate = depRepo.findById(depDetail.getId()).get();
            depUpdate.setName(depDetail.getName());
            depRepo.save(depUpdate);
        } 
        catch(Exception ex)
        {
            depUpdate = null;
        }
        return depUpdate;
    }
    
    public DepartmentModel deleteDepartment(DepartmentModel depDetail)
    {
        try
        {
            depRepo.deleteById(depDetail.getId());
        }
        catch(Exception ex)
        {
            return null;
        }
        return depDetail;
    }
    
}

My Test Class


import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.ArrayList;
import java.util.List;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Description;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.context.WebApplicationContext;

import com.bnpp.leavemanagement.controller.DepartmentController;
import com.bnpp.leavemanagement.model.DepartmentModel;
import com.bnpp.leavemanagement.service.DepartmentService;

@ExtendWith(MockitoExtension.class)
@WebMvcTest(DepartmentController.class)
@ContextConfiguration(classes = com.bnpp.leavemanagementsystem.LeaveManagementSystemApplicationTests.class)
public class DepartmentControllerTest {

    @MockBean
    DepartmentService depService;
    
    @Autowired
    private MockMvc mockMvc;
    
    @InjectMocks
    DepartmentController departmentController;
    
    @Autowired
    private WebApplicationContext webApplicationContext;
    
    @Test
    @Description("Should return a list of DepartmentModel objects when called")
    void shouldReturnListOfDepartmentModel() throws Exception
    {
        DepartmentModel depModel = new DepartmentModel();
        depModel.setId(1L);
        depModel.setName("Mock");
        
        List<DepartmentModel> listDepmodel = new ArrayList<>();
        listDepmodel.add(depModel);
        
        Mockito.when(depService.getAllDepartments()).thenReturn(listDepmodel);
        
        mockMvc.perform(MockMvcRequestBuilders.get("/department"))
        .andDo(print())
        .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.size()", Matchers.is(1)))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(1))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].name").value("Mock"));
    }

}

My Controller class

package com.bnpp.leavemanagement.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.bnpp.leavemanagement.dao.DepartmentRepository;
import com.bnpp.leavemanagement.model.DepartmentModel;
import com.bnpp.leavemanagement.service.DepartmentService;

@RestController
public class DepartmentController 
{
    @Autowired
    DepartmentService depService;
    
    
    @GetMapping("/department")
    public ResponseEntity<List<DepartmentModel>> getDepartments()
    {
        List<DepartmentModel> allDepartment = depService.getAllDepartments();
        if(allDepartment.size() == 0)
        {
            return new ResponseEntity( HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity( allDepartment, HttpStatus.OK);
    }
    
    @GetMapping("/department/{id}")
    public ResponseEntity<DepartmentModel> fetchDepartmentById(@PathVariable("id") int id)
    {
        DepartmentModel resDep = depService.fetchDepartmentById(id);
        if(resDep == null)
        {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        else
        {
            return new ResponseEntity( resDep, HttpStatus.OK);
        }
    }
    
    @PostMapping("/department/create")
    public ResponseEntity<DepartmentModel> createDepartment(@RequestBody DepartmentModel depNew)
    {
        DepartmentModel resDep = depService.addDepartment(depNew);
        if(resDep == null)
        {
            return new ResponseEntity(HttpStatus.EXPECTATION_FAILED);
        }
        else
        {
            return new ResponseEntity( resDep, HttpStatus.CREATED);
        }
    }
    
    @PutMapping("/department/update")
    public ResponseEntity<DepartmentModel> updateDepartment(@RequestBody DepartmentModel depNew)
    {
        DepartmentModel resDep = depService.updateDepartment(depNew);
        if(resDep == null)
        {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        else
        {
            return new ResponseEntity( resDep, HttpStatus.OK);
        }
    }
    
    @DeleteMapping("/department/delete")
    public ResponseEntity<DepartmentModel> deleteDepartment(@RequestBody DepartmentModel depDel)
    {
        DepartmentModel resDep = depService.deleteDepartment(depDel);
        if(resDep == null)
        {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        else
        {
            return new ResponseEntity(HttpStatus.OK);
        }
    }
    
}
 
1

There are 1 answers

0
rieckpil On

The minimal viable test setup to use MockMvc with @WebMvcTest is the following:

@WebMvcTest(DepartmentController.class)
class DepartmentControllerTest {

    @MockBean
    DepartmentService depService;
    
    @Autowired
    private MockMvc mockMvc;

    @Test
    @Description("Should return a list of DepartmentModel objects when called")
    void shouldReturnListOfDepartmentModel() throws Exception {
        DepartmentModel depModel = new DepartmentModel();
        depModel.setId(1L);
        depModel.setName("Mock");
        
        List<DepartmentModel> listDepmodel = new ArrayList<>();
        listDepmodel.add(depModel);
        
        Mockito.when(depService.getAllDepartments()).thenReturn(listDepmodel);
        
        mockMvc.perform(MockMvcRequestBuilders.get("/department"))
        .andDo(print())
        .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.size()", Matchers.is(1)))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(1))
                .andExpect(MockMvcResultMatchers.jsonPath("$[0].name").value("Mock"));
    }
}

Explanation:

  • @InjectMocks is not necessary as with @MockBean you're adding a mocked version of DepartmentService to your Spring TestContext and Spring DI's mechanism will inject it to your DepartmentController

  • @ExtendWith(SpringExtension.class) is also redundant, as the meta annotation @WebMvcTest already activates the SpringExtension.class

  • You don't need @ContextConfiguration here as @WebMvcTest takes care to detect your Spring Boot entrypoint class and start a sliced context

If the test still doesn't work, please add all your dependencies, the way you structure your code, and your main Spring Boot class (annotated with @SpringBootApplication).

Further reads that might shed some light on this: