In questo caso aderire a un'asserzione per prova è una 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, alla:

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 sarebbe proprio il folletto . Sono corretto in questo assunto, o c'è qualche altro modo in cui posso affermare che ogni obiettivo era, in effetti, stato testato?


Vedo i fiordi!
Ross Patterson,

Risposte:


15

Le tre affermazioni sono essenzialmente un test. Stai testando il comportamento di un metodo in una raccolta, per assicurarti che ogni articolo sia stato un parametro per una chiamata specifica (ovvero che ogni articolo sia stato elaborato correttamente).

L'impostazione dei dati tre volte e in tre diversi metodi è dispendiosa e meno leggibile rispetto all'alternativa di avere più asserzioni.

La "regola" di asserzione singola riguarda più di fare asserzioni di tipi diversi negli stessi metodi (essenzialmente testare cose diverse), che in realtà non si applica in questo caso, in cui si sta verificando un singolo comportamento.


3
Infatti: la regola è più un'asserzione logica per Unit Test. Potresti raggrupparli in un livello superiore affermando che potresti riutilizzarli in diversi test.
Laurent Bourgault-Roy,

5

Ritengo che questa affermazione per regola di test esista per mantenere i test focalizzati su un problema. Se testate 20 cose in un test, è davvero difficile dire quale sia la vostra copertura. Sai che sta causando un problema quando non puoi nominare il metodo di test senza la parola e in esso. Ad esempio, se il tuo metodo di test viene chiamato con più precisione come testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur(), probabilmente stai testando troppo in un test.

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


3

Per il tuo esempio particolare, puoi cavartela con una "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.


L'ho già fatto prima. Non è un brutto modo di andare. È facile da leggere e puoi capire la natura di ciò che sta facendo.
CokoBWare,

1

Ho lottato anche con questo.

Il purista (in me) insiste su un'affermazione per test, quindi saprò * esattamente * dove sono esplose le cose.

E poi mi ritrovo a tagliare / incollare molto dello stesso codice di configurazione del test ridondante. Dopo il terzo o quarto strato di questo, inizi a dire "Oy! Basta!"

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


1
Dovresti dare un'occhiata Assume. L'ho appena saputo oggi.
Wayne Werner,

1

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

Se il codice di configurazione per ciascun target è essenzialmente lo stesso, la suddivisione del test in più test individuali è probabilmente eccessiva.

Se target1e target2sono implementazioni diverse della stessa interfaccia, dovresti invece aggiungere un unit test all'interfaccia (e consentire al tuo framework di test di generare un test per ogni implementazione di quell'interfaccia).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.