【问题标题】:Mockito 3 Wanted but not invokedMockito 3 需要但未调用
【发布时间】:2020-07-24 00:48:07
【问题描述】:

我正在尝试学习 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 方法的行为,根据输入数据,如果值为空,则调用saveNullStudent 方法,否则调用saveStudent 方法调用。

我做错了什么?

【问题讨论】:

    标签: java junit mockito


    【解决方案1】:

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

    你需要更改mock,所以使用thenCallRealMethod()调用真正的方法。

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

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

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

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

    【讨论】:

    • HI @是的,如果我像这样更新我的测试用例,那么它就可以工作了。 @Test void saveStudentWithMockTest() { StudentService studentService = mock(StudentService.class); when(studentService.processStudent("studentA")).thenCallRealMethod(); studentService.processStudent("studentA");验证(学生服务,次(1))。保存学生(“学生A”);但是如果我的 saveStudent 方法实际上是在数据库中保存数据,并且因为现在我使用的是 thenCallRealMethod,那么它实际上会保存在 DB 中,这不是破坏了 mockito 的全部目的吗?
    • 您不需要调用真正的saveStudentsaveNullStudent 方法,只有processStudent 应该用作真正的方法。然后使用模拟的保存方法,您可以检查它们是否被正确调用 - 就像您在测试中所做的那样。这应该工作......
    【解决方案2】:

    您应该只模拟您要测试的类的依赖项。我的意思是,如果StudentService 类有任何全局变量,比如其他服务或存储库类,那么这些就是你应该模拟的类。 StudentService 类本身应该是真实的。在您的情况下,更好的测试是检查两个测试用例的 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();
        }
    
    }
    

    【讨论】:

    • 嗨@space-cadet,是的,我知道,但现在我的 StudentService 类中没有任何其他依赖项。现在我只想验证行为测试,根据输入数据,如果值为 null 则调用 saveNullStudent 方法,否则调用 saveStudent 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多