I am unable to run a unit test for my spring boot application at the Service Layer as it gives me null pointer exception at line List<Student> expectedList = studentService.findAl();
. But if I invoked the mock directly it works List<Student> expectedList = studentRepository.findAll();
. The studentRepository is inject in the studentService. Can anyone illustrate what the problem is?
TestClass:
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());
}
}
and the Repository:
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
}
the service interface:
public interface StudentService {
public List<Student> findAl();
public Student findById(long id);
public Student saveOrUpdate(Student student);
public void deleteById(long id);
}
and the service implementation:
@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);
}
}
I did some modifications to your code. The change that I did was in the StudentServiceImpl
class. I removed the @Autowired
annotation and did constructor injection.
@Service
public class StudentServiceImpl implements StudentService {
private final StudentRepository studentRepository;
public StudentServiceImpl(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
//others are same
}
And in the test class.
@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());
}
}
Now I can see the test passing.
Also, read this article which says "Get rid of @InjectMocks".
I hope it helps you:) Thanks a lot.
The mock you are configuring here:
StudentRepository studentRepository = mock(StudentRepository.class);
Is not injected into the service. Remove the initialisation of studentRepository inside your test and just use the one you have already annotated with @Mock.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.