Spring Boot RESTFUL控制器的单元测试

问题描述 投票:0回答:2

我正在尝试对Spring Boot RESTFUL控制器进行单元测试,但是我收到了空指针异常。该应用程序具有一个取决于StudentControllerStudentService。这是控制器代码:

package com.demo.student.demo.controller;

import com.demo.student.demo.annotation.ApiDescription;
import com.demo.student.demo.entity.Student;
import com.demo.student.demo.entity.StudentDto;
import com.demo.student.demo.service.StudentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/v1/students")
@Api(description = "This is a general description for StudentController RESTFUL Controller")
public class StudentController {

    private StudentService studentService;
    private ModelMapper modelMapper;

    public StudentController(ModelMapper modelMapper, StudentService studentService){
        this.studentService = studentService;
        this.modelMapper = modelMapper;
    }

    private StudentDto convertToDto(Student student) {
        StudentDto studentDto = modelMapper.map(student, StudentDto.class);
        return studentDto;
    }

    private Student convertToEntity(StudentDto studentDto) {
        Student student = modelMapper.map(studentDto, Student.class);
        return student;
    }

    @GetMapping
    @ApiOperation("Returns a list of all students in the system.")
    @ApiDescription("FIND_ALL_STUDENTS.md")
    public List<StudentDto> findAll(){
        List<Student> students = studentService.findAl();
        return students.stream()
                .map(student -> convertToDto(student))
                .collect(Collectors.toList());
    }

    @GetMapping("/{id}")
    @ApiOperation("Returns a specific Student by his/her identifier. 404 if does not exist.")
    @ApiDescription("FIND_STUDENT_BY_ID.md")
    public StudentDto findById(@PathVariable("id") long id){
        return convertToDto(studentService.findById(id));
    }

    @PostMapping
    @ApiOperation("Creates/Updates a new Student.")
    @ApiDescription("SAVE_OR_UPDATE_STUDENT.md")
    public StudentDto saveOrUpdate(@RequestBody StudentDto studentDto) {
        Student student = convertToEntity(studentDto);
        student.setUsername(student.getEmail() + "----" + student.getId());
        Student studentCreated = studentService.saveOrUpdate(student);
        return convertToDto(studentCreated);
    }

    @DeleteMapping("/{id}")
    @ApiOperation("Deletes a Student from the system. 404 if the Student's identifier is not found.")
    @ApiDescription("DELETE_STUDENT_BY_ID.md")
    public void deleteById(@PathVariable("id") long id){
        studentService.deleteById(id);
    }

}

这是服务实现代码:

package com.demo.student.demo.service;

import com.demo.student.demo.entity.Student;
import com.demo.student.demo.exception.StudentNotFoundException;
import com.demo.student.demo.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


@Service
public class StudentServiceImpl implements StudentService {

    private StudentRepository studentRepository;

    @Autowired
    public StudentServiceImpl(StudentRepository studentRepository){
        this.studentRepository = studentRepository;
    }

    @Override
    public List<Student> findAl() {
        return studentRepository.findAll();
    }

    @Override
    public Student findById(long id) {
        return  studentRepository.findById(id).orElseThrow(() -> new StudentNotFoundException(id));
    }

    @Override
    public Student saveOrUpdate(Student student) {
        studentRepository.save(student);
        return student;
    }

    @Override
    public void deleteById(long id) {
        if(this.findById(id) != null)
            studentRepository.deleteById(id);
    }

}

这是控制器的测试类:

package com.demo.student.demo.controller;

import com.demo.student.demo.entity.Student;
import com.demo.student.demo.service.StudentService;
import com.demo.student.demo.service.StudentServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
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.test.web.servlet.MockMvc;

import java.util.Arrays;
import java.util.List;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(StudentController.class)
class StudentControllerTest {

    private final static String URI = "/v1/students";

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private StudentService studentService;

    @Test
    void findAll() throws Exception {    
        // given
        Student student = new Student(1, "test", "[email protected]");
        List<Student> students = Arrays.asList(student);
        given(studentService.findAl()).willReturn(students);

        // when + then
        mockMvc.perform(get(URI))
                .andExpect(status().isOk())
                .andExpect(content().json("[{'id':1,'email':'[email protected]'}]"));
    }

}

[运行测试时,我收到指向StudentController类中代码行的NULL POINTER EXCEPTION,学生服务将在其中检索所有学生数据:List<Student> students = studentService.findAl();

java.lang.NullPointerException: null
    at com.demo.student.demo.controller.StudentController.findAll

谁能告诉我这是什么问题?

java spring-boot unit-testing mockito mockmvc
2个回答
0
投票

以这种方式注释您的测试课程。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

自动为此:

@Autowired
private WebApplicationContext wac;

这只是一个类变量:

private MockMvc mockMvc;

您的设置方法:

@Before
    public void setup() {

        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();

    }

在此行之前:

given(studentService.findAl())。willReturn(students);创建:

 StudentService studentService = org.mockito.Mockito.mock(StudentService.class);

它应该运行。


0
投票

测试中有两件事,首先,您要混合使用JUnit4和JUnit5,第二,您要尝试对付Spring Boot创建的模拟,不要。最后,您将为服务和注册行为创建一个新的模拟。

  1. 删除@RunWith批注,该批注用于JUnit4测试,JUnit5不需要。
  2. 删除您的@BeforeEach方法,因为这会干扰Spring Boot(通过MockMvc通过)和由@WebMvcTest创建的模拟程序所准备的@MockBean
  3. 从测试方法中删除StudentService studentService = mock(StudentService.class);@MockBean已创建一个模拟。这将创建一个新的模拟,而不绑定到控制器。

pro-tip:@Autowired中删除no-args构造函数和StudentController,Spring足够聪明,可以选择单个构造函数。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.