Перевірка у мокінгу

Вступ до тестування в 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...