Verifica il problema di copertura e riusabilità

1

Non sono molto bravo a scrivere test di unità, quindi ho un problema. Ho un binary_search_tree e sto scrivendo i test per i metodi insert e contains :

struct BinarySearchTree {};

TEST(BinarySearchTree, Insert) {
    BinarySearchTree t;
    t.insert(5);
    EXPECT_TRUE(t.contains(5));
}

TEST(BinarySearchTree, Contains) {
    BinarySearchTree t;
    t.insert(5);
    EXPECT_FALSE(t.contains(2);
    EXPECT_TRUE(t.contains(5);
}

Come puoi vedere, entrambi sono correlati tra loro e questi casi di test possono essere totalmente uguali perché:

  1. Testiamo l'inserimento inserendo un elemento e controllando che l'albero lo contenga.
  2. Testiamo l'esistenza dell'elemento inserendolo e controllando l'albero lo contiene.

Quindi ho 2 opzioni:

  1. Non scrivere test per contiene perché verrà testato nei test {inserimento, eliminazione, sostituzione, ecc.
  2. Scrivi quasi lo stesso contenuto in tutti questi test.

Cosa c'è di meglio?

    
posta Victor Polevoy 04.04.2016 - 12:25
fonte

2 risposte

4

I test unitari testano un'unità di codice, che può essere più grande di un metodo. Di solito non è possibile testare separatamente le coppie setter-getter e constructor-getter, e questo è OK. Avrai naturalmente casi di test come "contiene elementi inseriti" e "non contiene elementi che non sono stati inseriti". In questi casi, focalizzo i miei test su quel metodo che modifica la struttura. Qui, probabilmente utilizzerei un singolo test case per contiene-insert.

TEST(BinarySearchTree, ContainsInsertedElements) {
    BinarySearchTree t;
    EXPECT_FALSE(t.contains(5)); // precondition

    t.insert(5); // act

    EXPECT_TRUE(t.contains(5)); // assert
}

(e un altro caso in cui anche l'inserimento dello stesso elemento funziona di nuovo, e un caso di test non unitario di alto livello che posso inserire più numeri che dovrebbero produrre una struttura ad albero prevista.)

Per contains , potrei passare a più test white-boxy. In particolare, inserire e contiene probabilmente avrà un'operazione di ricerca comune che potrebbe essere testata con maggiore attenzione, e possiamo quindi supporre che anche questo contenga sia corretto.

Essenzialmente la duplicazione di un test solo perché il corpo del test utilizza due metodi non sembra una buona idea. I test sono codice e le linee guida come "non ripeterti" sono ancora valide (entro limiti ragionevoli). Inoltre, i test duplicati non aggiungono valore: se uno fallisce, anche l'altro. È meglio concentrarsi su contratti più generali dell'unità sottoposta a test, piuttosto che concentrarsi strettamente su ciascun metodo, indipendentemente da quanto possa essere inutile in isolamento.

    
risposta data 04.04.2016 - 13:51
fonte
5

I test case, se fatti bene, hanno due scopi:

  1. Controllano che nessuna funzionalità esistente si sia rotta quando si apportano modifiche al codice in futuro;
  2. Documentano come deve essere usato il codice e come si comporta.

Se hai appena avuto un assegno,

TEST(BinarySearchTree, Insert) {
    BinarySearchTree t;
    t.insert(5);
    EXPECT_FALSE(t.contains(2));
    EXPECT_TRUE(t.contains(5));
}

Quindi non riesce a ottenere il secondo vantaggio: EXPECT_FALSE(t.contains(2)); è sepolto all'interno di un controllo Insert e quindi non è ovvio per l'utente.

Quindi, mentre è un po 'più codice per scrivere i due test, è molto più chiaro ciò che i test stanno facendo se lo fai. Questo è un enorme vantaggio rispetto al salvataggio di poche righe di codice.

    
risposta data 04.04.2016 - 12:32
fonte

Leggi altre domande sui tag