Mock 的验证

Java 测试入门

Maria Milusheva

Senior Software Engineer

动机:无返回值

在上一课及练习中,我们通过断言返回值来测试。

  • 但如果没有返回值呢?

  • 如果返回值不重要或信息不足呢?

示例:保存到数据库。

将文件保存到数据库的图示

Java 测试入门

示例:数据库

"数据库"——用于存储、管理和保护有组织数据集合的数字存储库。常见提供商有: 一些流行数据库的标志

  • 数据库服务器耐用、安全、可靠,且容量近乎无限

  • 真实数据库过于庞大复杂,不适合单元测试(但可用于集成测试)

Java 测试入门

示例:日志消息

假设我们在处理日志:

public class MessageProcessor {
    private InfoStore infoStore;  // Will store info log messages here
    private ErrorStore errorStore; // Will store error log messages here

    public void saveMessage(String message) {
        if (message.startsWith("[INFO]")) {
            infoStore.save(message);
        }
        if (message.startsWith("[ERROR]")) {
            errorStore.save(message);
        }
    }
}
Java 测试入门

InfoStore 与 ErrorStore

测试只需基础接口:

// Blueprints for InfoStore and ErrorStore
// Mocks don't need the mocked classes to be properly implemented
interface InfoStore {
    void save(String message);
}

interface ErrorStore {
    void save(String message);
}
Java 测试入门

Mockito 的 verify

不创建数据库,如何测试消息已被保存?

断言某个 mock 被使用:

import static org.mockito.Mockito.verify;

断言某个 mock 未被使用:

import static org.mockito.Mockito.verifyNoInteractions;
Java 测试入门

测试设置

@Test
void process_savesToInfoStore_whenInfoMessage() {
  InfoStore infoStore = mock(InfoStore.class);
  ErrorStore errorStore = mock(ErrorStore.class);
  MessageProcessor messageProcessor = new MessageProcessor(infoStore, errorStore);

String message = "[INFO] Process started."; messageProcessor.saveMessage(message); // Will use either InfoStore or ErrorStore
// Verify which one of the two databases was used verify(infoStore).save(message); verifyNoInteractions(errorStore); }
Java 测试入门

测试失败信息

如果我们改为创建这条消息:

String message = "[ERROR] Process failed!"

则会看到如下失败:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
Java 测试入门

更多验证技巧

我们可以精确验证被调用的次数:

import static org.mockito.Mockito.times;
List<String> messages = new ArrayList<>(); // Create list and add elements
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");

messageProcessor.saveMessageList(messages); // Save the three messages


verify(infoStore, times(3)).save("[INFO] Processing data...");
Java 测试入门

Passons à la pratique !

Java 测试入门

Preparing Video For Download...