我想为 spring 引导服务方法编写一个 mockito 测试用例
I want to write a mockito test case for a spring boot service method
这是服务方式。
@Override
public void removeStudentByID(Long studentId) throws StudentExistsException {
boolean exists = studentRepo.existsById(studentId);
if (!exists) {
throw new StudentExistsException("Student doesn't exist");
}
studentRepo.deleteById(studentId);
}
下面是我为它写的测试用例。
@Test
public void removeStudentByIdTest() throws StudentExistsException {
Student student = new Student(1, "Drake", "drake@gmail.com");
when(studentRepo.save(student)).thenReturn(student);
studentService.removeStudentByID(student.getId());
assertEquals(false, studentRepo.existsById(student.getId()));
}
它没有运行...
但是下面的代码有效。
public void removeStudent(String email) {
Student student = studentRepo.findByEmail(email);
studentRepo.delete(student);
}
@Test
public void removeStudentTest() throws StudentExistsException {
Student student = new Student(3, "Ben", "ben@gmail.com");
studentRepo.save(student);
studentService.removeStudent(student.getEmail());
assertEquals(false, studentRepo.existsById(student.getId()));
}
所以,作为菜鸟,我对如何让它在第一个中起作用有点困惑。或者他们两个都有问题。
要测试此代码:
@Service
public class StudentService {
@Override
public void removeStudentByID(Long studentId) throws StudentExistsException
boolean exists = studentRepo.existsById(studentId);
if (!exists) {
throw new StudentExistsException("Student doesn't exist");
}
studentRepo.deleteById(studentId);
}
}
我们可以像这样模拟/“单元测试”:
package com.example.demo;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class StudenServiceTests { // we only test StudentService, since we (sort of) trust studentRepository (tested it elsewehere/how)
@Mock // A Mock! (alternatively @MockBean)
private StudentRepository studentRepoMock;
@InjectMocks // A real service (with mocks injected;)!!! (alternatively @Autowired/...)
private StudentService testee; // this guy we want to test (to the bone!)
@Test // ..the "good case"
void removeStudentByIdExists() throws StudentExistsException {
// Given:
// we don't even need a student, only his id
// instruct mock for the "first interaction" (see testee code):
when(studentRepoMock.existsById(1L)).thenReturn(true);
// instruct mock for "second interaction" (see testee code):
doNothing().when(studentRepoMock).deleteById(1L); // we could also use ...delete(any(Long.class)) or ..anyLong();
// When: (do it!)
testee.removeStudentByID(1L);
// Then: Verify (interactions, with as exact as possible parameters ..Mockito.any***)
verify(studentRepoMock).existsById(1L); //.times(n) ...when you had a list ;)
verify(studentRepoMock).deleteById(1L);
}
@Test // .. the "bad (but correct) case"/exception
void removeStudentByIdNotExists() throws StudentExistsException {
// Given:
when(studentRepoMock.existsById(1L)).thenReturn(false);
// When:
StudentExistsException thrown = assertThrows(
StudentExistsException.class,
() -> testee.removeStudentByID(1L),
"Expected testee.removeStudentByID to throw, but it didn't");
// Then:
assertNotNull(thrown);
assertTrue(thrown.getMessage().contains("Student doesn't exist"));
}
}
...运行 与 mvn test
.
通过这两个测试用例,我们实现了给定 method/service.
的 100% 测试(和分支)覆盖率
但不要将其与“集成测试”(我们使用真正的 repo/data 基础)混淆,然后我们可以使用:
- JDBC Testing Support
- Test Annotations (
@Commit, @Rollback, @Sql*
)
- JdbcTemplate
- ...
“默认”(假设为空)数据库的示例,准备(和 @Rollback
):
package com.example.demo;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
@SpringBootTest
class StudentServiceIT { // .. here we try to test "all of our application" (as good as possible ..to the bone)
@Autowired //! real "bean", no mock... this is only auxilary for this test, we could use some other method to prepare & verify
private StudentRepository studentRepository;
@Autowired //!! "real service"
private StudentService studentService;
@Test
@Rollback // actually our test is "self-cleaning"...when no exceptions ;)
void removeStudentByIdExists() throws StudentExistsException {
// Given:
Student student = new Student(1L, "Drake", "drake@gmail.com");
studentRepository.save(student);
// When:
studentService.removeStudentByID(1L);
// Then:
assertFalse(studentRepository.findById(1L).isPresent());
}
@Test
@Rollback // in any case (if assumptions were wrong;)
void removeStudentByIdNotExists() throws StudentExistsException {
// Given:
// nothing, we assume "empty db"
// When:
StudentExistsException thrown = assertThrows(
StudentExistsException.class,
() -> studentService.removeStudentByID(1L),
"Expected testee.removeStudentByID to throw, but it didn't");
// Then:
assertNotNull(thrown);
assertTrue(thrown.getMessage().contains("Student doesn't exist"));
}
}
(运行 与: mvn failsafe:integration-test
)
谢谢to/Refs:
- Mockito test a void method throws an exception
- Difference between @Mock and @InjectMocks
我就是这样做的,让我知道是否合适。 :)
@Test
public void removeStudentByIdTest() throws StudentExistsException {
Student student = new Student(1, "Drake", "drake@gmail.com");
when(studentRepo.existsById(student.getId())).thenReturn(true);
studentService.removeStudentByID(student.getId());
verify(studentRepo).deleteById((long) 1);
}
这是服务方式。
@Override
public void removeStudentByID(Long studentId) throws StudentExistsException {
boolean exists = studentRepo.existsById(studentId);
if (!exists) {
throw new StudentExistsException("Student doesn't exist");
}
studentRepo.deleteById(studentId);
}
下面是我为它写的测试用例。
@Test
public void removeStudentByIdTest() throws StudentExistsException {
Student student = new Student(1, "Drake", "drake@gmail.com");
when(studentRepo.save(student)).thenReturn(student);
studentService.removeStudentByID(student.getId());
assertEquals(false, studentRepo.existsById(student.getId()));
}
它没有运行... 但是下面的代码有效。
public void removeStudent(String email) {
Student student = studentRepo.findByEmail(email);
studentRepo.delete(student);
}
@Test
public void removeStudentTest() throws StudentExistsException {
Student student = new Student(3, "Ben", "ben@gmail.com");
studentRepo.save(student);
studentService.removeStudent(student.getEmail());
assertEquals(false, studentRepo.existsById(student.getId()));
}
所以,作为菜鸟,我对如何让它在第一个中起作用有点困惑。或者他们两个都有问题。
要测试此代码:
@Service
public class StudentService {
@Override
public void removeStudentByID(Long studentId) throws StudentExistsException
boolean exists = studentRepo.existsById(studentId);
if (!exists) {
throw new StudentExistsException("Student doesn't exist");
}
studentRepo.deleteById(studentId);
}
}
我们可以像这样模拟/“单元测试”:
package com.example.demo;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class StudenServiceTests { // we only test StudentService, since we (sort of) trust studentRepository (tested it elsewehere/how)
@Mock // A Mock! (alternatively @MockBean)
private StudentRepository studentRepoMock;
@InjectMocks // A real service (with mocks injected;)!!! (alternatively @Autowired/...)
private StudentService testee; // this guy we want to test (to the bone!)
@Test // ..the "good case"
void removeStudentByIdExists() throws StudentExistsException {
// Given:
// we don't even need a student, only his id
// instruct mock for the "first interaction" (see testee code):
when(studentRepoMock.existsById(1L)).thenReturn(true);
// instruct mock for "second interaction" (see testee code):
doNothing().when(studentRepoMock).deleteById(1L); // we could also use ...delete(any(Long.class)) or ..anyLong();
// When: (do it!)
testee.removeStudentByID(1L);
// Then: Verify (interactions, with as exact as possible parameters ..Mockito.any***)
verify(studentRepoMock).existsById(1L); //.times(n) ...when you had a list ;)
verify(studentRepoMock).deleteById(1L);
}
@Test // .. the "bad (but correct) case"/exception
void removeStudentByIdNotExists() throws StudentExistsException {
// Given:
when(studentRepoMock.existsById(1L)).thenReturn(false);
// When:
StudentExistsException thrown = assertThrows(
StudentExistsException.class,
() -> testee.removeStudentByID(1L),
"Expected testee.removeStudentByID to throw, but it didn't");
// Then:
assertNotNull(thrown);
assertTrue(thrown.getMessage().contains("Student doesn't exist"));
}
}
...运行 与 mvn test
.
通过这两个测试用例,我们实现了给定 method/service.
的 100% 测试(和分支)覆盖率但不要将其与“集成测试”(我们使用真正的 repo/data 基础)混淆,然后我们可以使用:
- JDBC Testing Support
- Test Annotations (
@Commit, @Rollback, @Sql*
) - JdbcTemplate
- ...
“默认”(假设为空)数据库的示例,准备(和 @Rollback
):
package com.example.demo;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
@SpringBootTest
class StudentServiceIT { // .. here we try to test "all of our application" (as good as possible ..to the bone)
@Autowired //! real "bean", no mock... this is only auxilary for this test, we could use some other method to prepare & verify
private StudentRepository studentRepository;
@Autowired //!! "real service"
private StudentService studentService;
@Test
@Rollback // actually our test is "self-cleaning"...when no exceptions ;)
void removeStudentByIdExists() throws StudentExistsException {
// Given:
Student student = new Student(1L, "Drake", "drake@gmail.com");
studentRepository.save(student);
// When:
studentService.removeStudentByID(1L);
// Then:
assertFalse(studentRepository.findById(1L).isPresent());
}
@Test
@Rollback // in any case (if assumptions were wrong;)
void removeStudentByIdNotExists() throws StudentExistsException {
// Given:
// nothing, we assume "empty db"
// When:
StudentExistsException thrown = assertThrows(
StudentExistsException.class,
() -> studentService.removeStudentByID(1L),
"Expected testee.removeStudentByID to throw, but it didn't");
// Then:
assertNotNull(thrown);
assertTrue(thrown.getMessage().contains("Student doesn't exist"));
}
}
(运行 与: mvn failsafe:integration-test
)
谢谢to/Refs:
- Mockito test a void method throws an exception
- Difference between @Mock and @InjectMocks
我就是这样做的,让我知道是否合适。 :)
@Test
public void removeStudentByIdTest() throws StudentExistsException {
Student student = new Student(1, "Drake", "drake@gmail.com");
when(studentRepo.existsById(student.getId())).thenReturn(true);
studentService.removeStudentByID(student.getId());
verify(studentRepo).deleteById((long) 1);
}