in C#

Unit Test, un pò di confusione

Reading Time: 3 minutes

Inizierò questo post parlando di quello che non è Unit Test. Questo perchè molto spesso mi trovo a “lottare” con codice che NON è uno Unit Test.

Se stiamo scrivendo del codice che scrive dati all’interno di un database, o che legge dati da qualche dispositivo I/O, non siamo in presenza di Unit Test.

Gli Unit Test sono indipendenti da sistemi esterni e non si occupano del loro enviroment .

Se ci troviamo di fronte a codice che può fallire in base al tipo di configurazione del sistema in cui viene eseguito, non siamo in presenza di uno Unit Test.

Anche la creazione di codice che invia richieste multiple ad un servizio, non siamo in presenza di uno Unit Test .

Se siamo in presenza di una console application che accetta un input dall’utente e restituisce un output di conseguenza, e si verifica l’output, non siamo in presenza di uno Unit Test, ma di un test di un sistema end-to-end.

Credo di aver generato nel lettore un pò di perplessità.

Unit Test, cosa sono?

Gli Unit Test, isolano e testano singole parti del codice. Definizione piuttosto vaga, ma al tempo stesso precisa. In C# un elemento unitario è un metodo: quello che deve essere implementata è una procedura che consenta di testarne la funzionalità. Analizziamo la classe Calculator

public class Calculator
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}

che al suo interno ha un unico metodo Add che accetta in ingresso due parametri. Si vuole implementare uno Unit Test che consenta di verificarne il funzionamento. La soluzione più semplice è quello di creare un nuovo progetto Console Application dove eseguire il metodo precedente:

public class Program
{
    static void Main(string[] args)
    {
        var calculator = new Calculator();
        int result = calculator.Add(5, 6);
        if (result != 20)
            throw new InvalidOperationException();
    }
}

Nell’esempio precedente supponiamo che il valore di result non sia valido nel caso in cui il valore sia diverso da 20. Abbiamo realizzato un semplice Unit Test. Anche se il progetto realizzato è sicuramente funzionale, non è sicuramente una soluzione utilizzabile: sarebbe necessario eseguire più volte la stessa console application per eseguire test differenti.

Utilizzare Framework

La soluzione precedente è sicuramente “manuale” e non applicabile (in termini di tempistiche e realizzazione) per testare applicazioni in produzione. Vengo in aiuto degli sviluppatori una serie di framework per realizzazione test professionali. In Visual Studio è possibile aggiungere ad un progetto esistente un progetto di tipo Unit Test:

unit test

all’interno del quale è possibile definire gli Unit Test.

unit test

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var calculator = new Calculator();
        int result = calculator.Add(4, 3);
        Assert.AreEqual(7, result);
    }
}

L’esempio precedente definisce una nuova class chiamata UnitTest1 con all’interno un metodo chiamato TestMethod1. A questo punto eseguendo il test:

unit test

il risultato sarà Test Superato. Prima di passare all’analisi della sintassi del codice del test, facciamo un pò di refactoring per renderlo più comprensibile anche negli usi futuri:

[TestClass]
public class CalculatorTests
{
    [TestMethod]
    public void Adding_4_And_3_Should_Return_7()
    {
        var calculator = new Calculator();
        int result = calculator.Add(4, 3);
        Assert.AreEqual(7, result);
    }
}

Per prima cosa è stata rinominata la classe aggiungendo il suffisso Tests ad indicare che si tratta di un test. Inoltre il metodo è stato modificato con un nome più leggibile ad indicare che testerà la somma del numero 4 con il numero 3 e che il risultato dovrà essere 7. Il framework predefinito per effettuare i test in Visual Studio è MSTest. Veniamo quindi all’analisi dei decoratori utilizzati:

  • [TestClass]: indica a Visual Studio che la classe contiene uno Unit Test
  • [TestMethod]: indica a Visual Studio che il metodo a cui si riferisce è un metodo di test.

MSTest considera i metodi con i decoratori TestClass e TestMethod per eseguire gli Unit Test. Se vengono rimossi da una classe o da un metodo, questi non verranno considerati. In questo modo è possibile definire e modificare gli Unit Test in maniera semplice e senza dover modificare il codice dell’applicazione da testare.

Microsoft definisce il namespace UnitTesting con una serie di classi di utilità tra cui la classe Assert: meditante i metodi di questa classe è possibile definire se un test è passato o meno.