【问题标题】:Mockito Spring Boot gives Null Pointer ExceptionMockito Spring Boot 给出空指针异常
【发布时间】:2019-11-18 16:46:54
【问题描述】:

我无法在服务层为我的 Spring Boot 应用程序运行单元测试,因为它在 List<Student> expectedList = studentService.findAl(); 行给了我空指针异常。但是,如果我直接调用模拟,它可以工作List<Student> expectedList = studentRepository.findAll();。 studentRepository 被注入到 studentService 中。谁能说明问题是什么?
测试类:

import com.demo.student.demo.entity.Student;
import com.demo.student.demo.repository.StudentRepository;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.*;

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

import static org.junit.jupiter.api.Assertions.*;

public class StudentServiceImplTest {

    @Mock
    private StudentRepository studentRepository;

    @InjectMocks
    private StudentServiceImpl studentService;

    @Test
    public void findAll(){
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(1, "person1", "person1@mail.com"));
        studentList.add(new Student(2, "person2", "person2@mail.com"));

        when(studentRepository.findAll()).thenReturn(studentList);

        List<Student> expectedList = studentService.findAl();

        assertEquals(0, expectedList.size());
    }


}

和存储库:

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
}

服务接口:

public interface StudentService {

    public List<Student> findAl();
    public Student findById(long id);
    public Student saveOrUpdate(Student student);
    public void deleteById(long id);

}

以及服务实现:

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

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

    @Override
    public Student findById(long id) {
        Optional<Student> student = studentRepository.findById(id);
        boolean exist = student.isPresent();
        return exist? student.get() : null;
    }

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

    @Override
    public void deleteById(long id) {
        studentRepository.deleteById(id);
    }

}

【问题讨论】:

    标签: java spring unit-testing junit mockito


    【解决方案1】:

    我对您的代码做了一些修改。 我所做的更改是在 StudentServiceImpl 类中。我删除了@Autowired 注释并进行了构造函数注入。

    @Service
    public class StudentServiceImpl implements StudentService {
    
    private final StudentRepository studentRepository;
    
    public StudentServiceImpl(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }
    
    //others are same
    }
    

    在测试类中。

    @RunWith(MockitoJUnitRunner.class)
    public class StudentServiceImplTest {
    
    private StudentService studentService;
    private StudentRepository studentRepository;
    
    @Test
    public void findAll(){
        studentRepository = mock(StudentRepository.class);
        studentService = new StudentServiceImpl(studentRepository);
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student(1, "person1", "person1@mail.com"));
        studentList.add(new Student(2, "person2", "person2@mail.com"));
    
        when(studentRepository.findAll()).thenReturn(studentList);
    
        List<Student> expectedList = studentService.findAl();
    
        assertEquals(2, expectedList.size());
     }
    }
    

    现在我可以看到测试通过了。

    另外,请阅读此 article,上面写着“摆脱 @InjectMocks”。

    希望对你有帮助 :) 非常感谢。

    【讨论】:

    • 它成功了!,我还能够使用 autowire 和 mockbeans 以及 springbootest 注释运行它。但是请再问一个问题:为什么当我在@Before 中进行实例化时它不起作用?不应该在每次测试之前执行吗?
    • 当你使用springboottest注解时,你正在加载整个ApplicationContext。因此,至少目前这是一种首选方式。好的,我也检查一下。
    • @m.y.m Before 是一个 JUnit 4 注释。您正在使用 JUnit 5,其中的等价物是 Before each。 JUnit 5 忽略了 Before 注释。
    【解决方案2】:

    您在此处配置的模拟:

        StudentRepository studentRepository = mock(StudentRepository.class);
    

    没有注入到服务中。在你的测试中删除 studentRepository 的初始化,只使用你已经用 @Mock 注释的那个。

    【讨论】:

    • 它现在在该行给出空指针异常:when(studentRepository.findAll()).thenReturn(studentList);
    • 两件事,将 StudentRepository 模拟的初始化移到 StudentService 的初始化之上,并改用 StudentServiceImpl。
    • 我将 Mock 移到 InjectMocks 上方,并使用类实现 StudentServiceImpl 而不是接口,但没有任何改变。仍然是 NPE:when(studentRepository.findAll()).thenReturn(studentList);
    • @m.y.m 编辑您的问题并添加您现在使用的代码。
    • 另外,发布测试类的完整代码,从第 1 行开始。导入很重要。
    猜你喜欢
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    • 2018-12-31
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多