Verificatie bij mocken

Introductie tot testen in Java

Maria Milusheva

Senior Software Engineer

Motivatie: geen returnwaarden

In de vorige les en oefeningen testten we via assertions op returnwaarden.

  • Maar wat als er geen returnwaarden zijn?

  • Wat als returnwaarden niet belangrijk of informatief zijn?

Voorbeeld: opslaan in een database.

Afbeelding van een database met bestanden die erin worden opgeslagen

Introductie tot testen in Java

Voorbeeld: databases

Database - een digitale opslagplaats voor het bewaren, beheren en beveiligen van gestructureerde gegevens. Er zijn veel databaseproviders: De logo's van enkele populaire databases

  • Databaseservers zijn duurzaam, veilig, betrouwbaar en hebben vrijwel onbeperkte capaciteit

  • Echte databases zijn te groot en complex voor unit tests (wel bruikbaar in integratietests)

Introductie tot testen in Java

Voorbeeld: logberichten

Stel dat we logs verwerken:

public class MessageProcessor {
    private InfoStore infoStore;  // Slaat info-logberichten hier op
    private ErrorStore errorStore; // Slaat error-logberichten hier op

    public void saveMessage(String message) {
        if (message.startsWith("[INFO]")) {
            infoStore.save(message);
        }
        if (message.startsWith("[ERROR]")) {
            errorStore.save(message);
        }
    }
}
Introductie tot testen in Java

InfoStore en ErrorStore

Voor de test zijn alleen basisinterfaces nodig:

// Blueprints voor InfoStore en ErrorStore
// Mocks hebben geen volledig geïmplementeerde klassen nodig
interface InfoStore {
    void save(String message);
}

interface ErrorStore {
    void save(String message);
}
Introductie tot testen in Java

Mockito verify

Hoe testen we dat een bericht is opgeslagen zonder databases te maken?

Controleer dat een mock is gebruikt:

import static org.mockito.Mockito.verify;

Controleer dat een mock niet is gebruikt:

import static org.mockito.Mockito.verifyNoInteractions;
Introductie tot testen in Java

Testsetup

@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); // Zal InfoStore of ErrorStore gebruiken
// Controleer welke van de twee databases is gebruikt verify(infoStore).save(message); verifyNoInteractions(errorStore); }
Introductie tot testen in Java

Testfoutmeldingen

Wat als het bericht dat we maken in plaats daarvan is:

String message = "[ERROR] Process failed!"

Dan zien we testfouten zoals:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
Introductie tot testen in Java

Meer verificatietrucs

We kunnen exact controleren hoe vaak een log is aangeroepen:

import static org.mockito.Mockito.times;
List<String> messages = new ArrayList<>(); // Maak lijst en voeg elementen toe
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");
                messages.add("[INFO] Processing data...");

messageProcessor.saveMessageList(messages); // Sla de drie berichten op


verify(infoStore, times(3)).save("[INFO] Processing data...");
Introductie tot testen in Java

Laten we oefenen!

Introductie tot testen in Java

Preparing Video For Download...