2009-11-23 14 views
11

Sto scrivendo alcuni test NUnit per le operazioni di database. Ovviamente, se Add() fallisce, allora anche Get() avrà esito negativo. Tuttavia, sembra ingannevole quando entrambi gli errori Add() e Get() falliscono perché sembra che ci siano due problemi invece di uno solo.Come si ignora un test basato su un altro test in NUnit?

Esiste un modo per specificare un 'ordine' per le prove per l'esecuzione in, nel senso che se il primo test ha esito negativo, i seguenti test vengono ignorati?

Nella stessa riga, c'è un modo per ordinare le classi di test dell'unità? Ad esempio, vorrei eseguire i miei test per le operazioni di base del database prima dei test per i dati round-trip dall'interfaccia utente.

Nota: Questo è un po 'diverso che avere le prove dipendono l'uno dall'altro, è più come far sì che qualcosa funziona prima prima di eseguire una serie di test. È una perdita di tempo, ad esempio, eseguire una serie di operazioni di database se non è possibile ottenere una connessione al database in primo luogo.

Modifica: Sembra che ad alcune persone manchi il punto. Non sto facendo questo:

[Test] 
public void AddTest() 
{ 
    db.Add(someData); 
} 

[Test] 
public void GetTest() 
{ 
    db.Get(someData); 
    Assert.That(data was retrieved successfully); 
} 

Piuttosto, sto facendo questo:

[Test] 
public void AddTest() 
{ 
    db.Add(someData); 
} 

[Test] 
public void GetTest() 
{ 
    // need some way here to ensure that db.Add() can actually be performed successfully 
    db.Add(someData); 
    db.Get(somedata); 
    Assert.That(data was retrieved successfully); 
} 

In altre parole, voglio garantire che i dati possono essere aggiunti in primo luogo prima che io possa verificare se può essere recuperato. Si presume che io stia utilizzando i dati del primo test per passare il secondo test quando non è così. Sto cercando di assicurarmi che una sola operazione sia possibile prima di tentarne un'altra che dipende da essa.

Come ho detto già, è necessario assicurarsi che si può ottenere una connessione al database prima di eseguire operazioni di database. O che puoi aprire un file prima di eseguire operazioni sui file. Oppure connettiti a un server prima di testare le chiamate API. O ... hai capito il punto.

+1

La risposta accettata è ** errata **! Vedi i commenti – Graviton

risposta

-3

creare una variabile globale e viceversa sia di prova per Get a meno Add Impostare a true (fare questo nell'ultima riga di Add):

public boolean addFailed = false; 
public void testAdd() { 
    try { 
     ... old test code ... 
    } catch (Throwable t) { // Catch all errors 
     addFailed = true; 
     throw t; // Don't forget to rethrow 
    } 
} 
public void testGet() { 
    if (addFailed) return; 
    ... old test code ... 
} 
+0

Grazie. Non è molto elegante, ma sembra che NUnit non supporti questa funzionalità in modo nativo. –

+1

Quello che vuoi è un hack, quindi la soluzione è anche una;) –

+0

Non sono un fan di questa soluzione. Il metodo testGet non è passato, non è stato eseguito. Dovrebbe essere segnalato come tale. –

1

non credo che sia possibile out-of scatola.

In ogni caso, la classe di progettazione prova come descritto renderà il codice di prova molto fragile.

+0

Non sto eseguendo il test 'Add()' per aggiungere prima dati nel database, quindi eseguire il test 'Get()' per ottenere i dati. Piuttosto, voglio assicurarmi che 'Add()' funzioni prima del test 'Get()', un po 'come dire "Ok, posso aggiungere dati nel database? Bene, ora aggiungi questo test e vedi se riesco a recuperare esso ". –

0

MbUnit sembra avere un DependsOnAttribute che ti consentirebbe di fare ciò che vuoi.

Se l'altro dispositivo di prova o con un metodo non riesce allora questa prova non corsa. Inoltre, la dipendenza forza questo test per eseguirsi dopo quelli da da cui dipende .

Non so nulla di NUnit però.

+0

Grazie, è praticamente esattamente quello che stavo cercando. È ancora presto che posso passare a MbUnit se lo desidero, quindi esaminerò il problema. –

14

NUnit supporta una "Assume.That" sintassi per setup.This convalida è documentata come parte del Theory (grazie clairestreb).Nello spazio dei nomi NUnit.Framework è una classe Assume. Per citare la documentazione:

/// Provides static methods to express the assumptions 
/// that must be met for a test to give a meaningful 
/// result. If an assumption is not met, the test 
/// should produce an inconclusive result. 

Quindi, nel contesto:

public void TestGet() { 
    MyList sut = new MyList() 
    Object expecting = new Object(); 
    sut.Put(expecting); 
    Assume.That(sut.size(), Is(1)); 
    Assert.That(sut.Get(), Is(expecting)); 
} 
+2

Questa dovrebbe essere la risposta accettata, un modo eccellente per dichiarare le dipendenze, e "inconcludente" è esattamente il risultato giusto, che nella maggior parte dei framework di test diventa arancione: significa che è ancora necessario fare qualcosa. – Abel

+1

7 anni dopo, ma continuo a tornare a questo post, quindi ecco il doc: http://nunit.org/index.php?p=theory&r=2.5 – clairestreb

5

I test dovrebbero mai dipendono l'uno dall'altro. Hai appena scoperto perché. I test che dipendono l'uno dall'altro sono fragili per definizione. Se sono necessari i dati nel DB per il test per Get(), inserirli nel passaggio di installazione.

+0

Tranne che non è fragile. Ti manca il punto. È necessario assicurarsi che alcune cose siano disponibili prima di poter eseguire i test. Nel mio caso, devo assicurarmi che 'Add()' funzioni perché senza di esso, 'Get()' non avrà alcun dato da ottenere. Non importa se è nel setup o no perché sto usando 'Add()' nel mio test 'Get()', ma devo assicurarmi che 'Add()' funzioni effettivamente prima di eseguire il test. –

+4

Questo è il motivo per cui il mocking e lo stubing servono. Nel test per 'Get()', dovresti essere in grado di fornire dati fittizi per l'uso di Get() affinché il test possa essere eseguito senza 'Add()'. Questo potrebbe significare passare una sottoclasse di 'Add()' che non fa nulla che potrebbe causare il fallimento. Il punto è che un test unitario dovrebbe testare solo l'unità in questione. Ci sarà un modo per testare Get() senza test Add(). Se ottieni la correzione che stai chiedendo, non puoi sapere se 'Get()' funziona o meno se 'Add()' è rotto. Significa che non puoi ottenere un'istantanea affidabile del tuo sistema. – jcdyer

+0

@Daniel T. Ti manca il punto. I test dovrebbero essere sempre indipendenti l'uno dall'altro. Ciò significa che l'uso di 'Add()' in un test per 'Get()' non è una buona idea. Se si interrompe 'Add()', anche i test per 'Get()' si interromperanno. Il tuo test non è isolato. Chi dice che è necessario usare 'Add()' per preparare il DB per 'Get()' ... – EricSchaefer

2

Penso che il problema è che stai usando NUnit per eseguire qualcosa di diverso dal tipo di test delle unità che NUnit è stato creato per funzionare.

In sostanza, si desidera che AddTest venga eseguito prima di GetTest e si desidera che NUnit interrompa l'esecuzione dei test in caso di errore di AddTest.

Il problema è che è antitetico al collaudo dell'unità - i test dovrebbero essere completamente indipendenti e funzionare in qualsiasi ordine.

Il concetto standard Unit Testing è che se si dispone di un test attorno alle funzionalità 'Aggiungi', quindi è possibile utilizzare il 'Aggiungi' funzionalità nel test 'Get' e non preoccuparsi di se 'Aggiungi' opera all'interno del 'Prendi' il test. Conosci i lavori "Aggiungi": ne hai una prova.

Il principio "PRIMO" (http://agileinaflash.blogspot.com/2009/02/first.html) descrive come devono comportarsi i test dell'unità. Il test che si desidera scrivere viola sia "I" (isolato) che "R" (ripetibile).

Se sei preoccupato che la connessione al database scenda tra i tuoi due test, ti consiglio che anziché collegarsi ad un vero database durante il test, il tuo codice dovrebbe usare una sorta di interfaccia dati, e per il test, dovresti usare un'interfaccia simulata. Se il punto del test è per esercitare la connessione al database, è possibile che si stia semplicemente utilizzando lo strumento sbagliato per il lavoro, che in realtà non è un test unitario.

+0

Quello che hai detto ha molto senso, ma ho ancora difficoltà a capire come posso isolare 'Get()' da 'Add()'. Per come la vedo io, è come avere una scatola vuota. Devi essere in grado di mettere qualcosa dentro la scatola prima di poter verificare se riesci a tirarlo fuori. –

+0

Sono praticamente isolati come possono essere. Se si desidera 'Get()', è ovviamente necessario 'Mettere()' prima nello stesso test (o nell'impostazione). L'isolamento deriva dal fatto che i tuoi due test stanno testando cose completamente diverse: i tuoi primi test 'Put()' e il tuo secondo test 'Get()'. Se "Put()" fallisce, entrambi falliranno, ma va bene. Non esiste una regola di test unitario che dice che se un'area del sistema si rompe, dovrebbe interrompere esattamente un test - deve solo interrompere * almeno * un test, si spera che uno di questi test specificamente quell'area. –

+0

Ho avuto un colloquio con un collega e ha detto che, anche se in teoria, sarebbe stato bello prevenire i fallimenti a cascata, raramente nella pratica si verificano casi in cui un guasto a cascata ostacola effettivamente qualsiasi cosa. In altre parole, se si hanno più di 200 test e il test per vedere se i dati possono essere recuperati dal database non è riuscito, sarebbe bello ignorare il resto dei test poiché anch'essi falliranno automaticamente. Ma poiché i test generalmente vengono eseguiti rapidamente e dovrebbero essere raggruppati in base al livello che stai testando, dovrebbe essere abbastanza facile vedere la traccia del problema. –

0

Non è possibile assumere alcun ordine di esecuzione del test, pertanto è necessario verificare eventuali prerequisiti all'interno delle classi di test.

Segrega il test Aggiungi in una classe di test, ad es. Aggiungi test e inserisci i test Get in un'altra classe di test, ad es. classe GetTests.

Nel metodo [TestFixtureSetUp] della classe GetTests, verificare di disporre dell'accesso al database funzionante (ad esempio il lavoro di Add), e in caso contrario, Assert.Ignore o Inconcludente, come si ritiene opportuno.

Questo interromperà l'apparecchio di prova GetTests quando i suoi prerequisiti non saranno soddisfatti, e salterà cercando di eseguire uno dei test unitari in esso contenuti. (penso! Sono un principiante nUnit.)

Problemi correlati