Domanda

Mi è stato chiesto di scrivere un'applicazione di test che deve testare una nuova procedura memorizzata su più righe in un database, in sostanza voglio fare qualcosa del genere:


[Test]
public void TestSelect()
{
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        Assert.AreEqual(old.Rows[0]["column"],ne_.Rows[0]["column"]);
    }
}

Quando eseguo questo test, se 1 riga non corrisponde all'altra, l'intero test fallisce; vorrei invece contare quante volte è stata approvata l'asserzione e quante volte ha fallito. C'è un modo per farlo con NUnit?

Mi rendo conto che NUnit potrebbe essere eccessivo e questo è un compito semplice senza di esso ... Volevo solo impararlo. ;)

È stato utile?

Soluzione

1) Se gli ID sono costanti e non vengono cercati durante l'esecuzione del test, creare un dispositivo di test unità separato per ciascun ID. In questo modo saprai quali ID stanno effettivamente fallendo. Vedi qui per una scrittura sui problemi con i test basati sui dati:
http://googletesting.blogspot.com/2008/09/tott -data-driven-traps.html

2) Se devi cercare dinamicamente l'id, rendendo impossibile creare un dispositivo per ogni id, usa il suggerimento di akmad con una modifica. Mantenere un elenco di ID in cui i valori non sono uguali e aggiungere l'elenco al messaggio di errore. Sarà estremamente difficile diagnosticare un test fallito che indica solo il numero di errori, poiché non saprai quale ID causa gli errori.

3) Non so quanto sarebbe difficile fare in NUnit, ma in PyUnit, quando abbiamo bisogno di eseguire test su dati generati dinamicamente, creiamo dinamicamente dispositivi di test e li colleghiamo alla classe TestCase in modo da avere un test fallito per ogni dato che non passa. Anche se immagino che questo sarebbe molto più difficile senza le abilità dinamiche di Python.

Altri suggerimenti

Sembra che tu stia solo affermando la cosa sbagliata. Se vuoi controllare tutti i valori e poi affermare che non ci sono errori (o mostrare il numero di errori), prova questo:

[Test]
public void TestSelect()
{
    int errors = 0;
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        if (old.Rows[0]["column"] != new_.Rows[0]["column"])
        {
            errors++;
        }            
    }

    Assert.AreEqual(0, errors, "There were " + errors + " errors.");
}

So che la domanda riguarda specificamente NUnit, ma abbastanza interessante, Gallio / MbUnit ha una funzione che consente di correre e catturare più asserzioni contemporaneamente.

[Test]
public void MultipleTest()
{
    Assert.Multiple(() =>
    {
       Assert.IsTrue(blabla);
       Assert.AreEqual(pik, pok);
       // etc.
    }
}

Assert.Multiple sta rilevando tutte le asserzioni non riuscite e le segnalerà alla fine del test.

Conterrei il numero di righe che non corrispondono e quindi scriverei un'asserzione che confronterà questo numero con 0 e restituirebbe il numero di stringhe non corrispondenti nel messaggio.

puoi anche usare Assert.Greater per questo.

P.S. In linea di principio dovresti provare a fare una asserzione per unit test. Questa è la sostanza.

Bene, potresti dichiarare un contatore e quindi affermare il valore del contatore per determinare il passaggio / fallimento

Inoltre, è possibile eseguire gran parte del lavoro nell'impostazione del test, quindi creare più test.

Non sono chiaro il motivo per cui hai bisogno di tutte le affermazioni sostenute nello stesso test.

In base all'obiettivo che hai definito, l'intero test dovrebbe fallire se una riga non corrisponde a un'altra. Contare il numero di volte in cui un'affermazione passa o fallisce ti dà meno informazioni di un confronto tra il risultato che ti aspettavi e quello che hai effettivamente ottenuto.

Di recente ho avuto lo stesso problema. Ho combinato l'idea di contare gli errori con la menzione di Assert da parte di Yann Trevin in un metodo di estensione per IEnumberable che mi permette di fare cose come:

[Test]
public void TestEvenNumbers()
{
    int[] numbers = new int[] { 2, 4, 12, 22, 13, 42 };
    numbers.AssertAll((num) => Assert.That((num % 2) == 0, "{0} is an odd number", num));
}

Che risulta nell'output di NUnit:

TestEvenNumbers:
  5 of 6 tests passed; 0 inconclusive
FAILED: 13:   13 is an odd number
  Expected: True
  But was:  False

  Expected: 6
  But was:  5

E la soluzione al problema del PO sarebbe:

[Test]
public void TestSelect()
{
    ids.AssertAll(CheckStoredProcedures);
}

private void CheckStoredProcedures(Id id)
{
    DataTable old = Database.call("old_stored_proc",id);
    DataTable new_ = Database.call("new_stored_proc",id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

Ecco il metodo di estensione (nota che ho usato "Tutto" anziché "Più" per coerenza con la terminologia di Linq):

using System;
using System.Text;
using System.Collections.Generic;
using NUnit.Framework;

public static class NUnitExtensions
{
    public static void AssertAll<T>(this IEnumerable<T> objects, Action<T> test)
    {
        int total = 0;
        int passed = 0;
        int failed = 0;
        int inconclusive = 0;
        var sb = new StringBuilder();
        foreach (var obj in objects)
        {
            total++;
            try
            {
                test(obj);
                passed++;
            }
            catch (InconclusiveException assertion)
            {
                inconclusive++;
                string message = string.Format("INCONCLUSIVE: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
            catch (AssertionException assertion)
            {
                failed++;
                string message = string.Format("FAILED: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
        }

        if (passed != total)
        {
            string details = sb.ToString();
            string message = string.Format("{0} of {1} tests passed; {2} inconclusive\n{3}", passed, total, inconclusive, details);
            if (failed == 0)
            {
                Assert.Inconclusive(message);
            }
            else
            {
                Assert.AreEqual(total, passed, message);
            }
        }
    }
}

Puoi utilizzare [TestCase ()] se un semplice elenco di ID codificato.

[Test]
[TestCase(1234)]
[TestCase(5678)]
[TestCase(7654)]
public void TestSelect(int id)
{
    DataTable old = Database.call("old_stored_proc", id);
    DataTable new_ = Database.call("new_stored_proc", id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

Questo genererà tre test separati per ciascun ID e qualunque sia il runner di test nunit che usi mostrerà i conteggi pass / fail.

Se è necessario generare un elenco dinamico di ID, consigliamo di utilizzare [TestCaseSource ()] attributo .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top