2013-08-15 5 views
5

Sto tentando di seguire più da vicino la pratica dell '"asserzione per unit test". Non è sempre possibile, ma lo trovo utile per individuare gli errori.Esiste un attributo per evitare errori di test dell'unità in cascata in MSTest?

Per esempio potrei avere qualcosa di simile:

var toTest; 

[TestInitialize] 
Init() { 
    toTest = // Create toTest 
} 

[TestMethod] 
TestIsCreated() { 
    Assert.IsNotNull(toTest); 
} 

[TestMethod] 
TestIsProperty1Setup() { 
    Assert.IsNotNull(toTest.Property1); 
    // Maybe some more tests on Property1 
} 

// More tests for other properties... 

Il problema è se la creazione di totest dovesse fallire, allora tutti gli altri test di unità non riescono troppo. Quindi possiamo aggiungere un controllo per questo in questo modo:

... 

[TestMethod] 
TestIsProperty1Setup() { 
    if (toTest == null) Assert.Inconclusive() 
    Assert.IsNotNull(toTest.Property1); 
    // Maybe some more tests on Property1 
} 

... 

Questo fermerà i guasti a cascata e punta al problema esatto. Se la riga // Create toTest restituisce un valore null, ottengo esattamente un errore del test di un'unità e un numero di test più inconcludenti. Quando aggiusto il test fallito, passa tutto il resto.

Ci sono due posti in cui questo cade. Uno è il fatto che ora ho ripetuto il codice all'inizio di quasi tutti i test unitari.

Il secondo problema è quando voglio installare e controllare un oggetto più complesso (in questo esempio fittizio totest ha anche una serie):

[TestMethod] 
TestArrayIsNotNull() { 
    if (toTest == null) Assert.Inconclusive(); 
    Assert.IsNotNull(toTest.Array); 
} 

[TestMethod] 
TestArrayIsInitilizedWithOneElement() { 
    if (toTest == null) Assert.Inconclusive(); 
    if (toTest.Array == null) Assert.Inconclusive(); 
    Assert.AreEqual(1, toTest.Array.Count()) 
} 

[TestMethod] 
TestArrayIsInitilizedWithCorrectElement() { 
    if (toTest == null) Assert.Inconclusive(); 
    if (toTest.Array == null) Assert.Inconclusive(); 
    if (toTest.Array.Count() != 1) Assert.Inconclusive(); 
    // Assert something about toTest.Array[0] 
} 

Ora c'è codice più duplicato per ogni singolo test, e ancora più importante, gli Assert devono essere mantenuti in sincronia tra diversi test, il che significa che un piccolo cambiamento può incresparsi in molti test unitari.

Idealmente mi piacerebbe avere un attributo che si trova nella parte superiore di ogni test e esegue il test solo se i test di "prerequisito" passano. Potrebbe sembrare qualcosa di simile:

[TestMethod] 
[OnlyRunIfOtherTestPasses(TestIsCreated())] 
TestArrayIsNotNull() { 
    Assert.IsNotNull(toTest.Array); 
} 

[TestMethod] 
[OnlyRunIfOtherTestPasses(TestArrayIsNotNull())] 
TestArrayIsInitilizedWithOneElement() { 
    Assert.AreEqual(1, toTest.Array.Count()) 
} 

[TestMethod] 
[OnlyRunIfOtherTestPasses(TestArrayIsInitilizedWithOneElement())] 
TestArrayIsInitilizedWithCorrectElement() { 
    // Assert something about toTest.Array[0] 
} 

i test di unità sono ora molto semplice - non vi siano doppioni e mantenere test sincronizzati con i loro 'prerequisiti' è ora automatico.

C'è qualcosa del genere? O c'è una caratteristica completamente diversa che posso usare per ottenere lo stesso effetto?

Sono consapevole che ci sono quasi certamente problemi con il riferimento a un metodo di test in un attributo ad un altro metodo di test - probabilmente dovresti usare una stringa che è codificata nel nome del metodo (quindi cosa succede se il metodo cambia nome o il metodo non esiste). Sono sicuro che ci sono anche potenziali problemi con riferimenti circolari. Ma nonostante tutti questi problemi, qualcuno deve aver affrontato questo problema. Qualcuno può segnalarlo a me?

+1

IMHO hai troppa logica nei test di unità. Dovrebbero essere concisi e non contenere molta logica. Inoltre, non dovrebbero dipendere da altri test. Penso che tu debba ripensare al tuo approccio. – Belogix

+0

Quando dici "ripensare il tuo approccio" intendi riconsiderare come vengono scritti i test unitari (non dovrei controllare se toTest è sempre nullo), o ripensare le dipendenze della classe sotto test (toTest non dovrebbe avere un array che deve essere impostato)? – Jonny

+0

Duplicato di: http://stackoverflow.com/questions/15871933/how-to-stop-mstest-tests-execution-on-first-failure – BartoszKP

risposta

0

La dipendenza tra i test è sconsigliata. Possibile soluzione al problema: se si lancia un'eccezione nel caso in cui la creazione di "toTest" non dovesse funzionare (o si usi un Assert ordinario) nel metodo di inizializzazione del test, allora credo che i test del gruppo non verranno eseguiti affatto. È anche possibile utilizzare l'inizializzazione della classe statica (http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.classinitializeattribute.aspx). Tuttavia, tutti i test verranno comunque contrassegnati come non riusciti.

+0

Se lancio un'eccezione nel metodo TestInitialize, tutti i test dell'unità falliscono.Sto puntando esattamente a un test di unità per fallire se la creazione non funziona in modo che sia molto facile individuare il problema. – Jonny