我正在尝试对Spring Boot RESTFUL控制器进行单元测试,但是我收到了空指针异常。该应用程序具有一个取决于StudentController
的StudentService
。这是控制器代码:
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
谁能告诉我这是什么问题?
以这种方式注释您的测试课程。
@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);
它应该运行。
测试中有两件事,首先,您要混合使用JUnit4和JUnit5,第二,您要尝试对付Spring Boot创建的模拟,不要。最后,您将为服务和注册行为创建一个新的模拟。
@RunWith
批注,该批注用于JUnit4测试,JUnit5不需要。 @BeforeEach
方法,因为这会干扰Spring Boot(通过MockMvc
通过)和由@WebMvcTest
创建的模拟程序所准备的@MockBean
。 StudentService studentService = mock(StudentService.class);
。 @MockBean
已创建一个模拟。这将创建一个新的模拟,而不绑定到控制器。 pro-tip:从@Autowired
中删除no-args构造函数和StudentController
,Spring足够聪明,可以选择单个构造函数。