2009-08-02 8 views
20

Mi chiedo come qualcuno dovrebbe utilizzare Assert.Inconclusive().Uso di Assert.Inconclusive

Lo sto usando se il mio test di unità sarebbe in procinto di fallire per un motivo diverso da quello a cui è destinato il test.

Ad esempio, ho un metodo su una classe che calcola la somma di una matrice di valori. Sulla stessa classe, c'è anche un metodo per calcolare la media dell'elemento. È implementato chiamando sum e dividendolo per la lunghezza dell'array.

Scrivere un test di unità per Sum() è semplice. Tuttavia, quando scrivo un test per Average() e Sum() fallisce, probabilmente anche Average() ha esito negativo.

L'errore di Media non è esplicito sul motivo per cui ha fallito; ha fallito per una ragione diversa da quella per cui dovrebbe essere testata. Ecco perché controllerei se Sum() restituisce il risultato corretto, altrimenti I Assert.Inconclusive().

E 'da considerarsi una buona pratica? A cosa serve Assert.Inclusive? O dovrei piuttosto risolvere l'esempio precedente per mezzo di un Isolation Framework?

risposta

14

Quando utilizzo VS per generare i test di unità, ho ottenuto Assert.Inclusive per i metodi di test generati e in genere cambio l'asserzione in modo da qualcos'altro quando li lavoro. Uso i punti interrogativi di Assert.Inclusive nei risultati del test come indicatori per indicare rapidamente quali test non ho ancora completato.

Bene, è solo il modo in cui lo uso. Dal suo nome "Inconcludente", immagino che tu possa usare per indicare il tuo stato indeterministico finché documenterai cosa significa.

Tuttavia, dalla descrizione del tuo metodo Average(), penso che forse il tuo test unitario non sia abbastanza atomico da coprire solo una "unità", uno scenario specifico. A volte, scrivo 2 o 3 metodi di test unitari per un singolo metodo. Oppure puoi rompere il tuo metodo Average() in metodi più piccoli che coprono singole responsabilità. In questo modo, puoi testare l'unità con quei metodi più piccoli prima di testare l'unità con uno Average().


Johannes,

Questo è come vorrei attuare le Sum() e Average() metodi.

public static class MyMath 
{ 
    private static void ValidateInput(ICollection<int> numbers) 
    { 
     if (numbers == null) 
      throw new ArgumentNullException("numbers", "Null input. Nothing to compute!"); 
     if (numbers.Count == 0) 
      throw new ArgumentException("Input is empty. Nothing to compute!"); 
    } 

    public static int Sum(int[] numbers) 
    { 
     ValidateInput(numbers); 

     var total = 0; 
     foreach (var number in numbers) 
      total += number; 

     return total; 
    } 

    public static double Average(int[] numbers) 
    { 
     ValidateInput(numbers); 
     return Sum(numbers)/numbers.Length; 
    } 
} 

Per semplicità, ho solo buttare ArgumentException eccezioni il metodo ValidateInput(ICollection<int>). È inoltre possibile verificare la possibilità di overflow e lanciare OverflowException nel metodo ValidateInput(ICollection<int>).

Detto ciò, ecco come testare la funzione Average(int[]).

[TestMethod] 
public void AverageTest_GoodInput() 
{ 
    int[] numbers = {1, 2, 3}; 
    const double expected = 2.0; 
    var actual = MyMath.Average(numbers); 
    Assert.AreEqual(expected, actual); 
} 

[TestMethod] 
[ExpectedException(typeof(ArgumentNullException))] 
public void AverageTest_NullInput() 
{ 
    int[] numbers = null; 
    MyMath.Average(numbers); 
} 

[TestMethod] 
[ExpectedException(typeof(ArgumentException))] 
public void AverageTest_EmptyInput() 
{ 
    var numbers = new int[0]; 
    MyMath.Average(numbers); 
} 

Con questi test di installazione, posso essere certo che quando tutti i test passano, la mia funzione è corretta. Bene, tranne per il caso di overflow. Ora posso tornare al metodo ValidateInput(ICollection<int>) per aggiungere la logica per verificare l'overflow, quindi aggiungere un altro test per aspettarsi che il OverflowException venga generato per il tipo di input che causano un overflow. O farlo nell'ordine opposto se ti piace avvicinarti con TDD.

Spero che questo aiuti a chiarire l'idea.

+0

potresti per favore elaborare come ti avvicineresti a questo in questo caso molto speciale –

+0

grazie mille. quindi in sostanza stai dicendo che non è necessario scrivere un test esplicito per Sum(), ma testarlo tramite Average(). Dal punto di vista della copertura del codice, questo genera comunque lo stesso risultato. –

+1

Scriverò anche test per Sum(). Chi lo sa nel mio assonnato momento, potrei digitare il '-' invece del '/'. :) Con i test per Sum() sul posto, se ho ottenuto tutti i test per Sum() ma alcuni test per Average() non riescono, posso essere molto certo che l'implementazione di Average() sia errata. Non sarò in grado di incolpare Sum() per aver causato che Average() sia errato. :) – tranmq

9

I Assert.Inclusive su test di unità non ho ancora scritto. A volte quando scrivo qualcosa mi rendo conto di alcuni casi angolari che non voglio perdere. Quindi salto rapidamente, scrivo il metodo di test con un nome descrittivo e aggiungo una singola riga di Assert.Inconclusive.

Il motivo è che fornisce documentazione su cose che devo testare senza interrompere troppo il flusso di lavoro. Permette anche di filtrare rapidamente i fallimenti dei test nella lista dei risultati. Avere un fallimento inconcludente significa che non ho rotto nulla, ho solo più test da scrivere.

+1

commenti Coppia: (1) di Visual Studio considera le prove che affermano di essere inconcludenti "test saltati" in Explorer Test. Questa categoria diventa quindi la tua lista di cose da fare. Jared ha già accennato a questo con "filtrare i fallimenti dei test", ma considero questo un grande vantaggio (2) Se si hanno più asserzioni in un singolo test (che superano), ma si asserisce inconcludente, l'intero test è considerato "saltato" ". In precedenza avevo usato inconcludenti per rappresentare la stessa situazione di Dennis C, ma sfavore questo ora, perché non è chiaro quale sia il risultato complessivo del test. – DPH

23

Test non conclusivo è un test per il quale non è possibile determinare il risultato. Ad esempio, cosa succede se hai un test che utilizza un qualche tipo di risorsa esterna (connessione Internet, ad esempio). Se la connessione non è attualmente disponibile, questo non significa in realtà che il test sia un errore. D'altra parte, non dovresti segnarlo come se fosse successo senza effettivamente attraversarlo. Quindi lo segnalo come inconcludente e questo può essere visto nel rapporto di prova.

NOTA: in generale, non è necessario utilizzare tali risorse esterne nei test, poiché ciò può rendere i test fragili.

Per i test non ancora completati, utilizzo l'attributo Explicit di MbUnit.

+2

Ho usato inconcludente in un e-mail unittest. Il codice invia e-mail, e devo controllare il layout visivo dalla casella di posta di Outlook –

7

Assert.Inconclusive indica che:

non ho ancora scritto la prova; ho creato solo il metodo di prova

oppure

La mia prova ha una dipendenza e che la dipendenza Non è disponibile. Per esempio

List<Customer> custs = o.GetAllCustomers(); 
if (custs.Count == 0) 
{ 
    Assert.Inconclusive("No customers to test"); 
    return; 
}