Проверка при мокировании

Введение в тестирование на 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

Как проверить, что сообщение сохранено, не создавая баз данных?

Проверить, что мок был вызван:

import static org.mockito.Mockito.verify;

Проверить, что мок не вызывался:

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

Давайте потренируемся!

Введение в тестирование на Java

Preparing Video For Download...