Codice di unit test in Visual C# in un'app di Windows Store

Questo argomento descrive come creare unit test per una classe Visual C# in un'app di Windows Store (anche nota come app di Windows Store) utilizzando Visual Studio Express 2012 per Windows 8 e il framework per unit test di Microsoft. La classe Rooter rammenta vagamente la teoria dei limiti di calcolo implementando una funzione che calcola una stima della radice quadrata di un numero specificato. Nell'app Maths questa funzione può quindi essere utilizzata per illustrare all'utente le varie operazioni che si possono eseguire con questa funzione matematica.

In questo argomento viene illustrato come utilizzare unit test come primo passaggio dell'attività di sviluppo. Secondo questo approccio devi innanzitutto scrivere un metodo di test che verifica il comportamento specifico del sistema che stai testando, quindi scriverai il codice che supera il test. Apportando modifiche nell'ordine in cui sono presentate le procedure riportate di seguito, puoi invertire questa strategia scrivendo per primo il codice che vuoi testare, quindi gli unit test.

In questo argomento si creerà inoltre una soluzione di Visual Studio e progetti distinti per gli unit test e la DLL da testare. Puoi anche includere gli unit test direttamente nel progetto DLL oppure creare soluzioni separate per gli unit test e la DLL.

Nota

Visual Studio Ultimate, VS Premium e VS Professional includono funzionalità aggiuntive per gli unit test.

  • VS Ultimate, VS Premium e VS Professional ti consentono di utilizzare un framework di unit test open source o di terze parti che abbia creato un adattatore di componente aggiuntivo per Esplora test di Microsoft. Puoi inoltre analizzare e visualizzare le informazioni di code coverage per i test.

  • Con VS Ultimate e VS Premium puoi eseguire i test dopo ogni compilazione.

  • VS Ultimate include anche Microsoft Fakes, un framework di isolamento per il codice gestito che ti permette di concentrare i test sul tuo codice sostituendo il codice di test per la funzionalità di sistema e di terze parti.

Per ulteriori informazioni, vedi Verifying Code by Using Unit Tests in MSDN Library.

In questo argomento

Create the solution and the unit test project

Verify that the tests run in Test Explorer

Add the Rooter class to the Maths project

Couple the test project to the app project

Iteratively augment the tests and make them pass

Debug a failing test

Refactor the code

Creare la soluzione e il progetto unit test

  1. Scegli Nuovo dal menu File, quindi Nuovo progetto.

  2. Nella finestra di dialogo Nuovo progetto espandi Installato, quindi Visual C# e scegli Windows Store. Scegli quindi Applicazione vuota dall'elenco di modelli di progetto.

  3. Assegna al progetto il nome Maths e verifica che l'opzione Crea directory per soluzione sia selezionata.

  4. In Esplora soluzioni scegli il nome della soluzione, scegli Aggiungi dal menu di scelta rapida, quindi Nuovo progetto.

  5. Nella finestra di dialogo Nuovo progetto espandi Installato, quindi Visual C# e scegli Windows Store. Scegli quindi Libreria unit test (applicazioni Windows Store) dall'elenco di modelli di progetto.

    Creare il progetto unit test

  6. Apri UnitTest1.cs nell'editor di Visual Studio.

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; using Maths; namespace RooterTests { [TestClass] public class UnitTest1 [TestMethod] public void TestMethod1() { }
    

    Come puoi notare:

    1. Ogni test viene definito tramite [TestMethod]. Un metodo di test deve restituire void e non può avere parametri.

    2. I metodi di test devono appartenere a una classe decorata con l'attributo [TestClass].

      Quando si eseguono i test, viene creata un'istanza di ogni classe di test. I metodi di test vengono chiamati in un ordine non specificato.

    3. Puoi definire metodi speciali che vengono richiamati prima e dopo ogni modulo, classe o metodo. Per ulteriori informazioni, vedi Utilizzo di membri Microsoft.VisualStudio.TestTools.UnitTesting in unit test in MSDN Library.

Verificare che i test siano eseguiti in Esplora test

  1. Inserisci codice di test in TestMethod1 del file UnitTest1.cs:

    [TestMethod] public void TestMethod1() { Assert.AreEqual(0, 0); }
    

    Nota che la classe Assert fornisce diversi metodi statici che puoi utilizzare per verificare i risultati nei metodi di test.

  2. Scegli Esegui dal menu Test, quindi Esegui tutto.

    Il progetto di test viene compilato ed eseguito. Compare la finestra di Esplora test con il test elencato in Test superati. Nel riquadro di riepilogo nella parte inferiore della finestra sono disponibili ulteriori dettagli sul test selezionato.

    Esplora test

Aggiungere la classe Rooter al progetto Maths

  1. In Esplora soluzioni seleziona il nome del progetto Maths. Scegli Aggiungi dal menu di scelta rapida, quindi Classe.

  2. Assegnare il nome Rooter.cs al file di classe.

  3. Aggiungi il seguente codice al file Rooter.cs della classe Rooter:

        public Rooter() { } // estimate the square root of a number public double SquareRoot(double x) { return 0.0; }
    
    
    

    La classe Rooter dichiara un costruttore e il metodo estimativo SqareRoot.

  4. Il metodo SqareRoot è solo un'implementazione minima, sufficiente per testare la struttura di base della configurazione di test.

Abbinare il progetto di test al progetto di app

  1. Aggiungi un riferimento all'app Maths al progetto RooterTests.

    1. In Esplora soluzioni scegli il progetto RooterTests, quindi scegli Aggiungi dal menu di scelta rapida.

    2. Nella finestra di dialogo Aggiungi riferimento - RooterTests espandi Soluzione e scegli Progetti. Seleziona quindi l'elemento Maths.

      Aggiungere un riferimento al progetto Maths

  2. Aggiungi un'istruzione using al file UnitTest1.cs:

    1. Apri UnitTest1.cs.

    2. Aggiungi questo codice sotto la riga using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;:

      using Maths;
      
  3. Aggiungi un test che utilizza la funzione Rooter. Aggiungi il seguente codice a UnitTest1.cpp.

        [TestMethod] public void BasicTest() { Maths.Rooter rooter = new Rooter(); double expected = 0.0; double actual = rooter.SquareRoot(expected * expected); double tolerance = .001; Assert.AreEqual(expected, actual, tolerance); }
    
  4. Compila la soluzione.

    Il nuovo test viene visualizzato in Esplora test nel nodo Test non eseguiti.

  5. In Esplora test scegli Esegui tutto.

    Test di base superato

A questo punto hai configurato il test e i progetti di codice. Hai inoltre verificato di poter eseguire i test che eseguono funzioni nel progetto di codice. Ora puoi iniziare a scrivere test e codice reali.

Incrementare i test in maniera iterativa e fare in modo che siano superati

  1. Aggiungi un nuovo test:

        [TestMethod] public void RangeTest() { Rooter rooter = new Rooter(); for (double v = 1e-6; v < 1e6; v = v * 3.2) { double expected = v; double actual = rooter.SquareRoot(v*v); double tolerance = ToleranceHelper(expected); Assert.AreEqual(expected, actual, tolerance); } }
    

    Suggerimento

    Ti suggeriamo di non modificare i test superati. Aggiungi invece un nuovo test, aggiorna il codice in modo che il test venga superato, quindi aggiungi un altro test e così via.

    Se gli utenti modificano i requisiti, disabilita i test che non risultano più corretti. Scrivi nuovi test e verificane il funzionamento, uno alla volta, sempre in modo incrementale.

  2. In Esplora test scegli Esegui tutto.

  3. Il test ha esito negativo.

    RangeTest non riuscito

    Suggerimento

    Subito dopo averlo scritto, verifica che ogni test abbia esito negativo. In questo modo eviti l'errore comune di scrivere un test che non ha mai esito negativo.

  4. Modifica il codice sottoposto a test in modo che il nuovo test venga superato. Modifica la funzione SqareRoot in Rooter.cs nel modo seguente:

        public double SquareRoot(double x) { double estimate = x; double diff = x; while (diff > estimate / 1000) { double previousEstimate = estimate; estimate = estimate - (estimate * estimate - x) / (2 * estimate); diff = Math.Abs(previousEstimate - estimate); } return estimate; }
    
  5. Compila la soluzione, quindi in Esplora test scegli Esegui tutto.

    Ora tutti e tre i test vengono superati.

Suggerimento

Sviluppa il codice aggiungendo i test uno alla volta. Assicurati che tutti i test vengano superati dopo ogni iterazione.

Eseguire il debug di un test non superato

  1. Aggiungi un altro test a UnitTest1.cs:

        // Verify that negative inputs throw an exception. [TestMethod] public void NegativeRangeTest() { string message; Rooter rooter = new Rooter(); for (double v = -0.1; v > -3.0; v = v - 0.5) { try { // Should raise an exception: double actual = rooter.SquareRoot(v); message = String.Format("No exception for input {0}", v); Assert.Fail(message); } catch (ArgumentOutOfRangeException ex) { continue; // Correct exception. } catch (Exception e) { message = String.Format("Incorrect exception for {0}", v); Assert.Fail(message); } } }
    
  2. In Esplora test scegli Esegui tutto.

    Il test ha esito negativo. Scegli il nome del test in Esplora test. L'asserzione non riuscita è evidenziata. Il messaggio di errore è visibile nel riquadro dei dettagli di Esplora test.

    NegativeRangeTests non riuscito

  3. Per verificare il motivo per cui il test non riesce, esegui la funzione un'istruzione alla volta:

    1. Imposta un punto di interruzione all'inizio della funzione SquareRoot.

    2. Dal menu di scelta rapida del test non superato scegli Esegui debug test selezionati.

      Quando l'esecuzione si ferma in corrispondenza del punto di interruzione, esegui il codice un'istruzione alla volta.

    3. Aggiungi codice al metodo Rooter per intercettare l'eccezione:

          public double SquareRoot(double x) { if (x < 0.0) { throw new ArgumentOutOfRangeException(); }
      
    1. In Esplora test scegli Esegui tutto per testare il metodo corretto e assicurarti di non aver introdotto una regressione.

Ora tutti i test vengono superati.

Tutti i test superati

Eseguire il refactoring del codice

Semplificare il calcolo centrale nella funzione SquareRoot.

  1. Modifica l'implementazione del risultato

    // old code //result = result - (result*result - v)/(2*result); // new code result = (result + v/result) / 2.0;
    
  2. Scegli Esegui tutto per testare il metodo di cui è stato eseguito il refactoring e assicurarti di non aver introdotto una regressione.

Suggerimento

Un set stabile di unit test corretti indica con sufficiente sicurezza che non sono stati introdotti bug in fase di modifica del codice.

Eseguire il refactoring del codice di test per eliminare il codice duplicato.

Come noterai, il metodo RangeTest imposta come hardcoded il denominatore della variabile di tolleranza utilizzata nel metodo Assert. Se prevedi di aggiungere altri test che utilizzano lo stesso calcolo di tolleranza, l'uso di un valore hardcoded in più posizioni potrebbe causare l'insorgere di errori.

  1. Aggiungi un metodo private alla classe Unit1Test per calcolare il valore di tolleranza e chiamare quindi tale metodo.

        private double ToleranceHelper(double expected) { return expected / 1000; } ... [TestMethod] public void RangeTest() { ... // old code // double tolerance = expected/1000; // new code double tolerance = ToleranceHelper(expected); Assert.AreEqual(expected, actual, tolerance); } ...
    
  2. Scegli Esegui tutto per testare il metodo di cui è stato eseguito il refactoring e assicurarti di non aver introdotto un errore.

Nota

Per aggiungere un metodo di supporto a una classe di test, non aggiungere l'attributo [TestMethod] al metodo. Esplora test non registra il metodo da eseguire.