Mockito 3 想要但没有调用

Mockito 3 Wanted but not invoked

我正在尝试学习 Mockito 3,我几乎查看了 google 搜索中的所有结果,但找不到有效的解决方案。 我在一个测试用例中调用 processStudent,该测试用例根据输入在内部调用另一个方法 saveStudentsaveNullStudent

 public String processStudent(String student) {
    System.out.println("StudentService.processStudent: it will process Student = " + student);
    String StudentRes;
    if (Objects.isNull(student)) {
        StudentRes = saveNullStudent(student);
        return StudentRes;
    } else {
        StudentRes = saveStudent(student);
        return StudentRes;
    }
}

public String saveNullStudent(String student) {
    System.out.println("StudentService.saveNullStudent: it will process then save Student = " + student);
    return student;
}

public String saveStudent(String student) {
    System.out.println("StudentService.saveStudent: it will process then save Student = " + student);
    return student;
}

我需要测试这两个案例,所以我的测试案例是

 @Test
void saveStudentWithMockTest() {
    StudentService StudentService = mock(StudentService.class);
    StudentService.processStudent("studentA");
    verify(StudentService, times(1)).saveStudent("studentA");
}

@Test
void saveStudentWithNullMockTest() {
    StudentService StudentService = mock(StudentService.class);
    StudentService.processStudent(null);
    verify(StudentService, times(1)).saveNullStudent(null);
}

但我得到了

Wanted but not invoked:
studentService.saveNullStudent(null);
-> at StudentServiceTest.saveStudentWithNullMockTest(StudentServiceTest.java:21)

However, there was exactly 1 interaction with this mock:
studentService.processStudent(null);
-> at StudentServiceTest.saveStudentWithNullMockTest(StudentServiceTest.java:20)

Gradle 文件

dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}

我不明白,这不是mockito的用途吗?

这个测试用例的重点不是单元测试,而是测试 processStudent 方法的行为,如果值为 null,则根据输入数据调用 saveNullStudent 方法,或者else saveStudent 方法被调用。

我做错了什么?

您在模拟对象上调用 processStudent,这意味着未使用原始代码。因此 save 方法没有被调用。

您需要更改模拟,因此使用 thenCallRealMethod() 调用真正的方法。

在您的第一个测试中,您必须添加如下一行:

when(StudentService.processStudent("studentA")).thenCallRealMethod()

在第二个测试中它是相似的,但是有另一个参数。 也许语法不是 100% 正确,因为我在没有任何 IDE 支持的情况下写这篇文章,但我想你明白了。

你应该先了解什么是模拟对象。那么解决方案将更有意义。

您应该只模拟要测试的 class 的依赖项。我的意思是,如果 StudentService class 有任何全局变量,如其他服务或存储库 classes 那些是你应该模拟的 classes。 StudentService class 本身应该是真实的。在您的案例中更好的测试是检查两个测试用例的 processStudent 方法的输出。例如:

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class StudentServiceTest {

    private final StudentService studentService = new StudentService();

    @Test
    public void saveStudentWithMockTest() {
        String result = studentService.processStudent("studentA");

        assertThat(result).isEqualToIgnoringCase("studentA");
    }

    @Test
    public void saveStudentWithNullMockTest() {
        String result = studentService.processStudent(null);

        assertThat(result).isNull();
    }

}