前言
在写单元测试的过程中,出现过许多次java.lang.NullPointerException,而这些空指针的错误又是不同原因造成的,本文从实际代码出发,研究一下空指针的产生原因。
一句话概括:空指针异常,是在程序在调用某个对象的某个方法时,由于该对象为null产生的。
所以如果出现此异常,大多数情况要判断测试中的对象是否被成功的注入,以及Mock方法是否生效。
基础
出现空指针异常的错误信息如下:
java.lang.NullPointerException
at club.yunzhi.workhome.service.WorkServiceImpl.updateOfCurrentStudent(WorkServiceImpl.java:178)
at club.yunzhi.workhome.service.WorkServiceImplTest.updateOfCurrentStudent(WorkServiceImplTest.java:137)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
这实际上是方法栈,就是在WorkServiceImplTest.java测试类的137行调用WorkServiceImpl.java被测试类的178行出现问题。
下面从两个实例来具体分析。
实例
(代码仅为了报错时方便分析,请勿仔细阅读,避免浪费时间)
1
目的:测试服务层的一个用于更新作业的功能。
接口
/**
* 更新作业分数
* @param id
* @param score
* @return
*/
Work updateScore(Long id, int score);
接口实现:
@Service
public class WorkServiceImpl implements WorkService {
private static final Logger logger = LoggerFactory.getLogger(WorkServiceImpl.class);
private static final String WORK_PATH = "work/";
final WorkRepository workRepository;
final StudentService studentService;
final UserService userService;
final ItemRepository itemRepository;
final AttachmentService attachmentService;
public WorkServiceImpl(WorkRepository workRepository, StudentService studentService, UserService userService, ItemRepository itemRepository, AttachmentService attachmentService) {
this.workRepository = workRepository;
this.studentService = studentService;
this.userService = userService;
this.itemRepository = itemRepository;
this.attachmentService = attachmentService;
}
...
@Override
public Work updateScore(Long id, int score) {
Work work = this.workRepository.findById(id)
.orElseThrow(() -> new ObjectNotFoundException("未找到ID为" + id + "的作业"));
if (!this.isTeacher()) {
throw new AccessDeniedException("无权判定作业");
}
work.setScore(score);
logger.info(String.valueOf(work.getScore()));
return this.save(work);
}
@Override
public boolean isTeacher() {
User user = this.userService.getCurrentLoginUser();
130 if (user.getRole() == 1) {
return false;
}
return true;
}
测试:
@Test
public void updateScore() {
Long id = this.random.nextLong();
Work oldWork = new Work();
oldWork.setStudent(this.c