In questo caso aderisce ad una asserzione per test di coerenza folle?

10

Ho una classe che sto testando. La classe ha una funzione: apply(List<IRule> rules, List<ITarget> targets);

In un test voglio assicurarmi che ogni obiettivo sia stato passato a una regola, a la:

rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));

Mi sembra che limitarmi a una singola affermazione di asserzione sarebbe piuttosto il hobgoblin . Sono corretto in questa ipotesi, o c'è un altro modo in cui posso affermare che ogni obiettivo è stato, in effetti, testato?

    
posta Wayne Werner 20.12.2012 - 21:49
fonte

5 risposte

15

I tre asseriti sono essenzialmente un test. Stai testando il comportamento di un metodo su una raccolta, per assicurarti che ogni elemento sia stato un parametro per una chiamata specifica (ad esempio, che ogni elemento è stato elaborato correttamente).

Impostare i dati su tre volte e in tre metodi diversi è uno spreco e meno leggibile rispetto all'opzione di avere più asserzioni.

La singola "regola" di asserzione consiste nel fare affermazioni di tipi diversi negli stessi metodi (essenzialmente testando cose diverse), che in realtà non si applica in questo caso, dove si sta testando per un singolo comportamento.

    
risposta data 20.12.2012 - 22:01
fonte
5

Sono convinto che questo asserisca una regola di prova per mantenere i test concentrati su un problema. Se metti alla prova 20 cose in un test, è davvero difficile dire qual è la tua copertura. Sai che sta causando un problema quando non puoi nominare il metodo di prova senza la parola e in esso. Ad esempio, se il tuo metodo di test verrebbe chiamato più accuratamente come testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur() , probabilmente stai testando troppo in un test.

Nel tuo caso, penso che probabilmente è giusto affermare tre volte. Se vuoi rendere più leggibile il tuo codice, puoi estrarre quei tre asseriti in un metodo chiamato assertWasCalledOnTargets(...) .

    
risposta data 20.12.2012 - 22:24
fonte
3

Per il tuo esempio particolare, puoi farcela con una "affermazione di asserzione" se fai qualcosa del tipo:

foreach target in targets
{
     rule1.AssertWasCalled(fnord => fnord.Test(target))
}

È quello che faccio per evitare di sentirmi in colpa per avere più asserzioni in un test.

    
risposta data 20.12.2012 - 22:10
fonte
1

Ho anche faticato con questo.

Il purista (in me) insiste su un assert per test quindi saprò * esattamente * dove le cose esplodono.

E poi mi trovo a tagliare / incollare un gran numero di codice di configurazione test ridondante. Dopo il terzo o il quarto strato di questo, inizi a dire "Oy! Basta!"

Il mio compromesso è stato quello di trovare gli aspetti che "mai" si rompono. E metterò insieme questi pezzi e poi aggiungerò un nuovo elemento che potrebbe rompersi. Per essere chiari, stratificare più aree volatili in un test sarebbe una violazione di questo compromesso.

    
risposta data 20.12.2012 - 22:03
fonte
1

Se il codice di configurazione per target1 è diverso dal codice di impostazione per target2 , questo tipo di taglio d'angolo tende a condurre alla fine un codice di inizializzazione di test troppo lungo. Questo a sua volta è un casino o finisce per essere refactored e riutilizzato. Se i tuoi test sono abbastanza complessi da giustificare il refactoring, il test probabilmente sta testando più di una cosa.

Se il codice di installazione per ciascun target è essenzialmente lo stesso, suddividere il test in più test individuali è probabilmente eccessivo.

Se target1 e target2 sono implementazioni differenti della stessa interfaccia, dovresti invece aggiungere un test di unità all'interfaccia (e consentire al framework di test di generare un test per ogni implementazione di tale interfaccia).

    
risposta data 20.12.2012 - 22:20
fonte

Leggi altre domande sui tag