Ověřování při mockování

Úvod do testování v Javě

Maria Milusheva

Senior Software Engineer

Motivace: Žádné návratové hodnoty

V předchozí lekci jsme testovali pomocí assertů na návratové hodnoty.

  • Co když ale nejsou žádné návratové hodnoty?

  • Co když návratové hodnoty nejsou důležité ani informativní?

Příklad: ukládání do databáze.

Grafika databáze se soubory ukládanými do ní

Úvod do testování v Javě

Příklad: Databáze

Databáze – digitální úložiště pro ukládání, správu a zabezpečení organizovaných kolekcí dat. Existuje mnoho poskytovatelů databází: Loga některých populárních databází

  • Databázové servery jsou odolné, bezpečné, spolehlivé a mají neomezenou kapacitu

  • Reálné databáze jsou příliš velké a složité pro unit testy (mohou být použity v integračních testech)

Úvod do testování v Javě

Příklad: Zprávy logu

Předpokládejme, že zpracováváme záznamy:

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);
        }
    }
}
Úvod do testování v Javě

InfoStore a ErrorStore

Pro fungování testu stačí základní rozhraní:

// 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);
}
Úvod do testování v Javě

Mockito verify

Jak otestovat, že byla zpráva uložena, aniž bychom vytvářeli databáze?

Assert, že mock byl použit:

import static org.mockito.Mockito.verify;

Assert, že mock nebyl použit:

import static org.mockito.Mockito.verifyNoInteractions;
Úvod do testování v Javě

Nastavení testu

@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); }
Úvod do testování v Javě

Zprávy o selhání testu

Co kdyby vytvořená zpráva byla místo toho:

String message = "[ERROR] Process failed!"

Pak uvidíme selhání testu takto:

Wanted but not invoked:
infoStore.save("[ERROR] Process failed!");
Actually, there were zero interactions with this mock.
Úvod do testování v Javě

Další techniky ověřování

Lze ověřit přesný počet volání záznamu:

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...");
Úvod do testování v Javě

Pojďme procvičovat!

Úvod do testování v Javě

Preparing Video For Download...