如何使用 mockito 和 junit 来测试我的 spring boot rest api?

how to use mockito and junit to test my spring boot rest api?

我是单元测试的新手,不知道如何使用 Mockito 和 Junit 测试 RESTFul API 和 Spring,首先我已经准备好 class 其中我用 @Before@Test 创建了两个方法,当我进入调试模式时它告诉我 hasSize 集合 return 0 不是 4.

@RunWith(SpringJUnit4ClassRunner.class)
public class EmployeControllerTest {
    private MockMvc mockMvc;
    @InjectMocks
    private EmployeController employeController ; 
    @Mock
    private EmployeService employeService ;

    @Before
    public void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        mockMvc=MockMvcBuilders.standaloneSetup(employeController).build();
    }
    @Test
    public void testgetAllEmployee() throws Exception{
        List<Employe> employes= Arrays.asList(
                new Employe("Hamza", "Khadhri", "hamza1007", "123")
                ,new Employe("Oussema", "smi", "oussama", "1234") );
        when(employeService.findAll()).thenReturn(employes);
        mockMvc.perform(get("/employe/dto"))
        .andExpect(status().isOk())
        .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
        .andExpect(jsonPath("$", hasSize(4)))
         .andExpect(jsonPath("$[0].nom", is("Hamza")))
         .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
         .andExpect(jsonPath("$[0].login", is("hamza1007")))
         .andExpect(jsonPath("$[0].mp", is("123")))
         .andExpect(jsonPath("$[1].nom", is("Oussema")))
         .andExpect(jsonPath("$[1].prenom", is("smi")))
         .andExpect(jsonPath("$[1].login", is("oussama")))
         .andExpect(jsonPath("$[1].mp", is("1234")));

        verify(employeService,times(1)).findAll();
        verifyNoMoreInteractions(employeService);
    }
}

这里是 EmployeController :

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @RestController
    @RequestMapping("/employe")
    public class EmployeController {
        @Autowired
        private EmployeService employeService;

        @Autowired
        private ModelMapper modelMapper;

        @GetMapping("/dto")
        public List<EmployeDTO> getEmployeDTOList(){
            try {
                    List<Employe> listemp=employeService.findAllEmployeActive();
                    return listemp.stream()
                        .map(emp ->convertToDto(emp))
                        .collect(Collectors.toList());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }

        private EmployeDTO convertToDto(Employe emp) {
            EmployeDTO empDto = modelMapper.map(emp, EmployeDTO.class);

            return empDto;
       }
   }

当我进入调试模式时,它告诉我有NullPointerException

如何正确使用mockitojunit才能通过考试?

我发现了一些潜在的问题:

首先,您正在呼叫

List<Employe> listemp=employeService.findAllEmployeActive();

在您的控制器的 getEmployeDTOList() 中,但是您的 Mockito 模拟写为:

when(employeService.findAll()).thenReturn(employes)

因此,您的测试可能无法正常工作,因为您的模拟从未发生过。

其次,您没有嘲笑您在控制器中自动装配的 ModelMapper。我 认为 Spring 仍会继续为您获取该组件(如果我在那里错了,请有人纠正我),但无论哪种方式,拥有您的单位都不是很好的做法测试依赖于外部库,因为您应该只关心控制器的功能。最好模拟 ModelMapper 使其 "always" 工作并编写单独的测试来验证您的映射。

我继续制作我自己的代码版本来测试。我将 hasSize 更改为 2 因为您在示例中只使用了两个元素。

这个测试对我有用:

@RunWith(SpringJUnit4ClassRunner.class)
public class EmployeeControllerTest {

    private MockMvc mockMvc;
    @InjectMocks
    private EmployeeController employeeController ; 
    @Mock
    private EmployeeService employeeService;
    @Mock
    private ModelMapper modelMapper;

    @Before
    public void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        mockMvc=MockMvcBuilders.standaloneSetup(employeeController).build();
    }

    @Test
    public void testgetAllEmployeeWithModelMapper() throws Exception{
        Employee emp1 = new Employee("Hamza", "Khadhri", "hamza1007", "123");
        Employee emp2 = new Employee("Oussema", "smi", "oussama", "1234");
        List<Employee> Employees= Arrays.asList(emp1, emp2);

        EmployeeDTO dto1 = new EmployeeDTO("Hamza", "Khadhri", "hamza1007", "123");
        EmployeeDTO dto2 = new EmployeeDTO("Oussema", "smi", "oussama", "1234");
        when(modelMapper.map(emp1,EmployeeDTO.class)).thenReturn(dto1);
        when(modelMapper.map(emp2,EmployeeDTO.class)).thenReturn(dto2);

        when(employeeService.findAll()).thenReturn(Employees);


        mockMvc.perform(get("/employe/dto"))
            .andExpect(status().isOk())
            .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
            .andExpect(jsonPath("$", hasSize(2)))
            .andExpect(jsonPath("$[0].nom", is("Hamza")))
            .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
            .andExpect(jsonPath("$[0].login", is("hamza1007")))
            .andExpect(jsonPath("$[0].mp", is("123")))
            .andExpect(jsonPath("$[1].nom", is("Oussema")))
            .andExpect(jsonPath("$[1].prenom", is("smi")))
            .andExpect(jsonPath("$[1].login", is("oussama")))
            .andExpect(jsonPath("$[1].mp", is("1234")));

        verify(employeeService,times(1)).findAll();
        verifyNoMoreInteractions(employeeService);

    }

}

如您所见,我创建了自己的 DTO 对象并将它们传回,这样 modelMapper 将始终按预期进行此单元测试。

这是有效的代码,但它忽略了对象 emp1:

 public void testgetAllEmployeeWithModelMapper() throws Exception{
         Employe emp1 = new Employe("Hamza", "Khadhri", "hamza1007", "123");
         Employe emp2 = new Employe("Oussem", "smi", "oussama", "1234");
         List<Employe> Employees= Arrays.asList(emp1, emp2);
         EmployeDTO dto1 = new EmployeDTO("Hamza", "Khadhri", "hamza1007", "123");
         EmployeDTO dto2 = new EmployeDTO("Oussem", "smi", "oussama", "1234");
         when(modelMapper.map(emp1,EmployeDTO.class)).thenReturn(dto1);
         when(modelMapper.map(emp2,EmployeDTO.class)).thenReturn(dto2);

         when(employeeService.findAll()).thenReturn(Employees);
         mockMvc.perform(get("/employe/dto"))
         .andExpect(status().isOk())
         .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
         .andExpect(jsonPath("$", hasSize(2)))
         .andExpect(jsonPath("$[0].nom", is("Hamza")))
         .andExpect(jsonPath("$[0].prenom", is("Khadhri")))
         .andExpect(jsonPath("$[0].login", is("Hamza1007")))
         .andExpect(jsonPath("$[0].mp", is("123")))
         .andExpect(jsonPath("$[1].nom", is("Oussema")))
         .andExpect(jsonPath("$[1].prenom", is("smi")))
         .andExpect(jsonPath("$[1].login", is("oussama")))
         .andExpect(jsonPath("$[1].mp", is("1234")));

     verify(employeeService,times(1)).findAll();
     verifyNoMoreInteractions(employeeService);
    }

}

控制台显示 jsonPath("$[0].nom" 期望 Oussema 因此,当我将其更改为对象 emp2 的 Oussema 时,它运行良好。不幸的是,它忽略了包含 Hamza 的对象 emp1, 个人而言,我只是在 Employe 和 EmployeDTO 中添加了两个构造函数。

这是 class 员工:

 public class Employe implements Serializable {



    @Id
    @Column(unique=true, nullable=false, precision=6)
    private Long id;
    @Column(precision=6)
    private BigDecimal cv;
    @Column(length=254)
    private String nom;
    @Column(length=254)
    private String prenom;
    @Column(length=254)
    private String login;
    @Column(length=254)
    private String mp;
    @Column(length=254)
    private String mail;
    @Column(precision=6)
    private BigDecimal idpointage;
    @Column(length=1)
    private Boolean actif;
    public Employe(String nom, String prenom, String login, String mp) {

        this.nom = nom;
        this.prenom = prenom;
        this.login = login;
        this.mp = mp;
    }

这是 class EmployeDTO:

public class EmployeDTO {
        private String nom;
        private String prenom;
        private String login ; 
        private String mp ; 


        public EmployeDTO(String nom, String prenom, String login, String mp) {

            this.nom= nom ; 
            this.prenom= prenom ; 
            this.login = login ; 
            this.mp=mp ;
        }