Esercitazione: Testare una libreria di classi .NET con .NET usando Visual Studio

Questa esercitazione illustra come automatizzare gli unit test aggiungendo un progetto di test a una soluzione.

Prerequisiti

Creare un progetto di unit test

Gli unit test forniscono test software automatici durante le fasi di sviluppo e pubblicazione. MSTest è uno dei tre framework di test tra cui è possibile scegliere. Gli altri sono xUnit e nUnit.

  1. Avviare Visual Studio.

  2. Aprire la soluzione ClassLibraryProjects creata in Creare una libreria di classi .NET usando Visual Studio.

  3. Aggiungere alla soluzione un nuovo progetto di unit test denominato "StringLibraryTest".

    1. Fare clic con il pulsante destro del mouse sulla soluzione in Esplora soluzioni e selezionare Aggiungi>Nuovo progetto.

    2. Nella pagina Aggiungi un nuovo progetto immettere mstest nella casella di ricerca. Scegliere C# o Visual Basic dall'elenco Linguaggio e quindi scegliere Tutte le piattaforme dall'elenco Piattaforma.

    3. Scegliere il modello progetto di test MSTest e quindi scegliere Avanti.

    4. Nella pagina Configura il nuovo progetto immettere StringLibraryTest nella casella Nome progetto. Scegliere quindi Avanti.

    5. Nella pagina Informazioni aggiuntive selezionare .NET 8 (anteprima) nella casella Framework. Scegli quindi Crea.

  4. Visual Studio crea il progetto e apre il file di classe nella finestra del codice con il codice seguente. Se il linguaggio che si vuole usare non viene visualizzato, modificare il selettore di linguaggio nella parte superiore della pagina.

    namespace StringLibraryTest;
    
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Sub TestSub()
    
            End Sub
        End Class
    End Namespace
    

    Il codice sorgente creato dal modello di unit test esegue le operazioni seguenti:

    Ogni metodo contrassegnato con [TestMethod] in una classe di test contrassegnata con [TestClass] viene eseguito automaticamente quando viene eseguito lo unit test.

Aggiungere un riferimento al progetto

Affinché il progetto di test funzioni con la classe StringLibrary, aggiungere un riferimento nel progetto StringLibraryTest al progetto StringLibrary.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo Dipendenze del progetto StringLibraryTest e selezionare Aggiungi riferimento al progetto dal menu di scelta rapida.

  2. Nella finestra di dialogo Gestione riferimenti espandere il nodo Progetti e selezionare la casella accanto a StringLibrary. L'aggiunta di un riferimento all'assembly StringLibrary consente al compilatore di trovare i metodi StringLibrary durante la compilazione del progetto StringLibraryTest.

  3. Seleziona OK.

Aggiungere ed eseguire metodi di unit test

Quando Visual Studio esegue uno unit test, esegue ogni metodo contrassegnato con l'attributo TestMethodAttribute in una classe contrassegnata con l'attributo TestClassAttribute. Un metodo di test termina quando viene trovato il primo errore o quando tutti i test contenuti nel metodo hanno avuto esito positivo.

I test più comuni chiamano i membri della classe Assert. Molti metodi assert includono almeno due parametri, uno dei quali corrisponde al risultato previsto del test, mentre l'altro corrisponde al risultato effettivo. Nella tabella seguente sono illustrati alcuni metodi chiamati più frequentemente della classe Assert:

Metodi Assert Funzione
Assert.AreEqual Verifica che due oggetti o valori siano uguali. L'asserzione ha esito negativo se i valori o gli oggetti non sono uguali.
Assert.AreSame Verifica che due variabili oggetto facciano riferimento allo stesso oggetto. Il metodo ha esito negativo se le variabili fanno riferimento a oggetti diversi.
Assert.IsFalse Verifica che una condizione sia false. Il metodo ha esito negativo se la condizione è true.
Assert.IsNotNull Verifica che un oggetto non sia null. Il metodo ha esito negativo se l'oggetto è null.

È anche possibile usare il metodo Assert.ThrowsException in un metodo di test per indicare il tipo di eccezione che dovrebbe generare. Il test ha esito negativo se l'eccezione specificata non viene generata.

Durante il test del metodo StringLibrary.StartsWithUpper, è possibile specificare alcune stringhe che iniziano con un carattere maiuscolo. In tal caso si prevede che il metodo restituisca true, quindi è possibile chiamare il metodo Assert.IsTrue. Analogamente, è possibile specificare alcune stringhe che iniziano con un valore diverso da un carattere maiuscolo. In tal caso si prevede che il metodo restituisca false, quindi è possibile chiamare il metodo Assert.IsFalse.

Poiché il metodo di libreria gestisce le stringhe, è anche necessario assicurarsi che gestisca correttamente una stringa vuota (String.Empty), una stringa valida senza caratteri e il cui Length è 0 e una stringa null che non è stata inizializzata. È possibile chiamare StartsWithUpper direttamente come metodo statico e passare un singolo argomento String. In alternativa, è possibile chiamare StartsWithUpper come metodo di estensione in una variabile di string assegnata a null.

Verranno definiti tre metodi, ognuno dei quali chiama un metodo Assert per ogni elemento in una matrice di stringhe. Verrà chiamato un overload del metodo che consente di specificare un messaggio di errore da visualizzare in caso di errore del test. Il messaggio identifica la stringa che ha causato l'errore.

Per creare i metodi di test:

  1. Nella finestra del codice UnitTest1.cs o UnitTest1.vb sostituire il codice con il codice seguente:

    using UtilityLibraries;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestStartsWithUpper()
            {
                // Tests that we expect to return true.
                string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsTrue(result,
                           string.Format("Expected for '{0}': true; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void TestDoesNotStartWithUpper()
            {
                // Tests that we expect to return false.
                string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " " };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void DirectCallWithNullOrEmpty()
            {
                // Tests that we expect to return false.
                string?[] words = { string.Empty, null };
                foreach (var word in words)
                {
                    bool result = StringLibrary.StartsWithUpper(word);
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word == null ? "<null>" : word, result));
                }
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    Imports UtilityLibraries
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Public Sub TestStartsWithUpper()
                ' Tests that we expect to return true.
                Dim words() As String = {"Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsTrue(result,
                           $"Expected for '{word}': true; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub TestDoesNotStartWithUpper()
                ' Tests that we expect to return false.
                Dim words() As String = {"alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " "}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsFalse(result,
                           $"Expected for '{word}': false; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub DirectCallWithNullOrEmpty()
                ' Tests that we expect to return false.
                Dim words() As String = {String.Empty, Nothing}
                For Each word In words
                    Dim result As Boolean = StringLibrary.StartsWithUpper(word)
                    Assert.IsFalse(result,
                           $"Expected for '{If(word Is Nothing, "<null>", word)}': false; Actual: {result}")
                Next
            End Sub
        End Class
    End Namespace
    

    Il test dei caratteri maiuscoli nel metodo TestStartsWithUpper include la lettera maiuscola greca alfa (U+0391) e la lettera maiuscola cirillico EM (U+041C). Il test dei caratteri minuscoli nel metodo TestDoesNotStartWithUpper include la lettera minuscola greca alfa (U+03B1) e la lettera minuscola cirillico Ghe (U+0433).

  2. Nella barra dei menu selezionare File>Salva UnitTest1.cs con nome o File>Salva UnitTest1.vb con nome. Nella finestra di dialogo Salva file con nome selezionare la freccia accanto al pulsante Salva e selezionare Salva con codifica.

    Visual Studio Save File As dialog

  3. Nella finestra di dialogo Conferma Salva con nome selezionare il pulsante per salvare il file.

  4. Nella finestra di dialogo Opzioni di salvataggio avanzate selezionare Unicode (UTF-8 con firma digitale) - Tabella codici 65001 dall'elenco a discesa Codifica e selezionare OK.

    Visual Studio Advanced Save Options dialog

    Se il salvataggio del codice sorgente come file con codifica UTF8 ha esito negativo, Visual Studio può salvarlo come file ASCII. In questo caso, il runtime non decodifica accuratamente i caratteri UTF8 all'esterno dell'intervallo ASCII e i risultati del test non saranno corretti.

  5. Nella barra dei menu selezionare Test>Esegui tutti i test. Se la finestra Esplora test non viene aperta, aprirla scegliendo Test>Esplora test. I tre test sono elencati nella sezione Test superati e nella sezione Riepilogo è riportato il risultato dell'esecuzione dei test.

    Test Explorer window with passing tests

Gestire gli errori di test

Se si esegue lo sviluppo basato su test (TDD), si scrivono prima i test e non riescono la prima volta che vengono eseguiti. Aggiungere quindi il codice all'app che rende il test riuscito. Per questa esercitazione è stato creato il test dopo aver scritto il codice dell'app convalidato, in modo da non aver visto l'esito negativo del test. Per verificare che un test non riesca quando si prevede che non riesca, aggiungere un valore non valido all'input di test.

  1. Modificare la matrice words del metodo TestDoesNotStartWithUpper per includere la stringa "Error". Non è necessario salvare il file perché Visual Studio salva i file aperti automaticamente quando viene creata una soluzione per eseguire i test.

    string[] words = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " };
    
    Dim words() As String = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " }
    
    
  2. Eseguire il test selezionando Test>Esegui tutti i test dalla barra dei menu. La finestra Esplora test indica che due test hanno avuto esito positivo e uno esito negativo.

    Test Explorer window with failing tests

  3. Selezionare il test non riuscito, TestDoesNotStartWith.

    Nella finestra Esplora test viene visualizzato il messaggio generato dal metodo Assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True". A causa dell'errore, non sono state testate stringhe nella matrice dopo il test di "Error".

    Test Explorer window showing the IsFalse assertion failure

  4. Rimuovere la stringa "Errore" aggiunta nel passaggio 1. Eseguire nuovamente il test. I test verranno superati.

Test della versione di rilascio della libreria

Ora che tutti i test sono stati superati durante l'esecuzione della compilazione Debug della libreria, eseguire i test un tempo aggiuntivo rispetto alla versione di rilascio della libreria. Esistono infatti alcuni fattori, ad esempio le ottimizzazioni del compilatore, in grado di generare a volte comportamenti diversi tra la versione di debug e quella di rilascio.

Per testare la versione di rilascio, seguire questa procedura:

  1. Nella barra degli strumenti di Visual Studio modificare la configurazione di compilazione da Debug a Rilascio.

    Visual Studio toolbar with release build highlighted

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto StringLibrary e selezionare Compila dal menu di scelta rapida per ricompilare la libreria.

    StringLibrary context menu with build command

  3. Eseguire gli unit test scegliendo Test>Esegui tutti i test dalla barra dei menu. I test avranno esito positivo.

Esecuzione del debug dei test

Se si usa Visual Studio come IDE, è possibile usare lo stesso processo illustrato in Esercitazione: Eseguire il debug di un'applicazione console .NET usando Visual Studio per eseguire il debug del codice usando il progetto di unit test. Invece di avviare il progetto di app ShowCase, fare clic con il pulsante destro del mouse sul progetto StringLibraryTests e scegliere Debug test dal menu di scelta rapida.

Visual Studio avvia il progetto di test con il debugger collegato. L'esecuzione verrà arrestata in qualsiasi punto di interruzione aggiunto al progetto di test o al codice della libreria sottostante.

Risorse aggiuntive

Passaggi successivi

In questa esercitazione è stata testata una libreria di classi. È possibile rendere disponibile la libreria ad altri utenti pubblicandola in NuGet come pacchetto. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Se si pubblica una libreria come pacchetto NuGet, altri utenti possono installarla e usarla. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Non è necessario distribuire una libreria come pacchetto. Può essere incluso in un'app console che la usa. Per informazioni su come pubblicare un'app console, vedere l'esercitazione precedente in questa serie:

Questa esercitazione illustra come automatizzare gli unit test aggiungendo un progetto di test a una soluzione.

Prerequisiti

Creare un progetto di unit test

Gli unit test forniscono test software automatici durante le fasi di sviluppo e pubblicazione. MSTest è uno dei tre framework di test tra cui è possibile scegliere. Gli altri sono xUnit e nUnit.

  1. Avviare Visual Studio.

  2. Aprire la soluzione ClassLibraryProjects creata in Creare una libreria di classi .NET usando Visual Studio.

  3. Aggiungere alla soluzione un nuovo progetto di unit test denominato "StringLibraryTest".

    1. Fare clic con il pulsante destro del mouse sulla soluzione in Esplora soluzioni e selezionare Aggiungi>Nuovo progetto.

    2. Nella pagina Aggiungi un nuovo progetto immettere mstest nella casella di ricerca. Scegliere C# o Visual Basic dall'elenco Linguaggio e quindi scegliere Tutte le piattaforme dall'elenco Piattaforma.

    3. Scegliere il modello progetto di test MSTest e quindi scegliere Avanti.

    4. Nella pagina Configura il nuovo progetto immettere StringLibraryTest nella casella Nome progetto. Scegliere quindi Avanti.

    5. Nella pagina Informazioni aggiuntive selezionare .NET 7 (supporto standard) nella casella Framework. Scegli quindi Crea.

  4. Visual Studio crea il progetto e apre il file di classe nella finestra del codice con il codice seguente. Se il linguaggio che si vuole usare non viene visualizzato, modificare il selettore di linguaggio nella parte superiore della pagina.

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Sub TestSub()
    
            End Sub
        End Class
    End Namespace
    

    Il codice sorgente creato dal modello di unit test esegue le operazioni seguenti:

    Ogni metodo contrassegnato con [TestMethod] in una classe di test contrassegnata con [TestClass] viene eseguito automaticamente quando viene eseguito lo unit test.

Aggiungere un riferimento al progetto

Affinché il progetto di test funzioni con la classe StringLibrary, aggiungere un riferimento nel progetto StringLibraryTest al progetto StringLibrary.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo Dipendenze del progetto StringLibraryTest e selezionare Aggiungi riferimento al progetto dal menu di scelta rapida.

  2. Nella finestra di dialogo Gestione riferimenti espandere il nodo Progetti e selezionare la casella accanto a StringLibrary. L'aggiunta di un riferimento all'assembly StringLibrary consente al compilatore di trovare i metodi StringLibrary durante la compilazione del progetto StringLibraryTest.

  3. Seleziona OK.

Aggiungere ed eseguire metodi di unit test

Quando Visual Studio esegue uno unit test, esegue ogni metodo contrassegnato con l'attributo TestMethodAttribute in una classe contrassegnata con l'attributo TestClassAttribute. Un metodo di test termina quando viene trovato il primo errore o quando tutti i test contenuti nel metodo hanno avuto esito positivo.

I test più comuni chiamano i membri della classe Assert. Molti metodi assert includono almeno due parametri, uno dei quali corrisponde al risultato previsto del test, mentre l'altro corrisponde al risultato effettivo. Nella tabella seguente sono illustrati alcuni metodi chiamati più frequentemente della classe Assert:

Metodi Assert Funzione
Assert.AreEqual Verifica che due oggetti o valori siano uguali. L'asserzione ha esito negativo se i valori o gli oggetti non sono uguali.
Assert.AreSame Verifica che due variabili oggetto facciano riferimento allo stesso oggetto. Il metodo ha esito negativo se le variabili fanno riferimento a oggetti diversi.
Assert.IsFalse Verifica che una condizione sia false. Il metodo ha esito negativo se la condizione è true.
Assert.IsNotNull Verifica che un oggetto non sia null. Il metodo ha esito negativo se l'oggetto è null.

È anche possibile usare il metodo Assert.ThrowsException in un metodo di test per indicare il tipo di eccezione che dovrebbe generare. Il test ha esito negativo se l'eccezione specificata non viene generata.

Durante il test del metodo StringLibrary.StartsWithUpper, è possibile specificare alcune stringhe che iniziano con un carattere maiuscolo. In tal caso si prevede che il metodo restituisca true, quindi è possibile chiamare il metodo Assert.IsTrue. Analogamente, è possibile specificare alcune stringhe che iniziano con un valore diverso da un carattere maiuscolo. In tal caso si prevede che il metodo restituisca false, quindi è possibile chiamare il metodo Assert.IsFalse.

Poiché il metodo di libreria gestisce le stringhe, è anche necessario assicurarsi che gestisca correttamente una stringa vuota (String.Empty), una stringa valida senza caratteri e il cui Length è 0 e una stringa null che non è stata inizializzata. È possibile chiamare StartsWithUpper direttamente come metodo statico e passare un singolo argomento String. In alternativa, è possibile chiamare StartsWithUpper come metodo di estensione in una variabile di string assegnata a null.

Verranno definiti tre metodi, ognuno dei quali chiama un metodo Assert per ogni elemento in una matrice di stringhe. Verrà chiamato un overload del metodo che consente di specificare un messaggio di errore da visualizzare in caso di errore del test. Il messaggio identifica la stringa che ha causato l'errore.

Per creare i metodi di test:

  1. Nella finestra del codice UnitTest1.cs o UnitTest1.vb sostituire il codice con il codice seguente:

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using UtilityLibraries;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestStartsWithUpper()
            {
                // Tests that we expect to return true.
                string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsTrue(result,
                           string.Format("Expected for '{0}': true; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void TestDoesNotStartWithUpper()
            {
                // Tests that we expect to return false.
                string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " " };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void DirectCallWithNullOrEmpty()
            {
                // Tests that we expect to return false.
                string?[] words = { string.Empty, null };
                foreach (var word in words)
                {
                    bool result = StringLibrary.StartsWithUpper(word);
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word == null ? "<null>" : word, result));
                }
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    Imports UtilityLibraries
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Public Sub TestStartsWithUpper()
                ' Tests that we expect to return true.
                Dim words() As String = {"Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsTrue(result,
                           $"Expected for '{word}': true; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub TestDoesNotStartWithUpper()
                ' Tests that we expect to return false.
                Dim words() As String = {"alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " "}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsFalse(result,
                           $"Expected for '{word}': false; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub DirectCallWithNullOrEmpty()
                ' Tests that we expect to return false.
                Dim words() As String = {String.Empty, Nothing}
                For Each word In words
                    Dim result As Boolean = StringLibrary.StartsWithUpper(word)
                    Assert.IsFalse(result,
                           $"Expected for '{If(word Is Nothing, "<null>", word)}': false; Actual: {result}")
                Next
            End Sub
        End Class
    End Namespace
    

    Il test dei caratteri maiuscoli nel metodo TestStartsWithUpper include la lettera maiuscola greca alfa (U+0391) e la lettera maiuscola cirillico EM (U+041C). Il test dei caratteri minuscoli nel metodo TestDoesNotStartWithUpper include la lettera minuscola greca alfa (U+03B1) e la lettera minuscola cirillico Ghe (U+0433).

  2. Nella barra dei menu selezionare File>Salva UnitTest1.cs con nome o File>Salva UnitTest1.vb con nome. Nella finestra di dialogo Salva file con nome selezionare la freccia accanto al pulsante Salva e selezionare Salva con codifica.

    Visual Studio Save File As dialog

  3. Nella finestra di dialogo Conferma Salva con nome selezionare il pulsante per salvare il file.

  4. Nella finestra di dialogo Opzioni di salvataggio avanzate selezionare Unicode (UTF-8 con firma digitale) - Tabella codici 65001 dall'elenco a discesa Codifica e selezionare OK.

    Visual Studio Advanced Save Options dialog

    Se il salvataggio del codice sorgente come file con codifica UTF8 ha esito negativo, Visual Studio può salvarlo come file ASCII. In questo caso, il runtime non decodifica accuratamente i caratteri UTF8 all'esterno dell'intervallo ASCII e i risultati del test non saranno corretti.

  5. Nella barra dei menu selezionare Test>Esegui tutti i test. Se la finestra Esplora test non viene aperta, aprirla scegliendo Test>Esplora test. I tre test sono elencati nella sezione Test superati e nella sezione Riepilogo è riportato il risultato dell'esecuzione dei test.

    Test Explorer window with passing tests

Gestire gli errori di test

Se si esegue lo sviluppo basato su test (TDD), si scrivono prima i test e non riescono la prima volta che vengono eseguiti. Aggiungere quindi il codice all'app che rende il test riuscito. Per questa esercitazione è stato creato il test dopo aver scritto il codice dell'app convalidato, in modo da non aver visto l'esito negativo del test. Per verificare che un test non riesca quando si prevede che non riesca, aggiungere un valore non valido all'input di test.

  1. Modificare la matrice words del metodo TestDoesNotStartWithUpper per includere la stringa "Error". Non è necessario salvare il file perché Visual Studio salva i file aperti automaticamente quando viene creata una soluzione per eseguire i test.

    string[] words = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " };
    
    Dim words() As String = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " }
    
    
  2. Eseguire il test selezionando Test>Esegui tutti i test dalla barra dei menu. La finestra Esplora test indica che due test hanno avuto esito positivo e uno esito negativo.

    Test Explorer window with failing tests

  3. Selezionare il test non riuscito, TestDoesNotStartWith.

    Nella finestra Esplora test viene visualizzato il messaggio generato dal metodo Assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True". A causa dell'errore, non sono state testate stringhe nella matrice dopo il test di "Error".

    Test Explorer window showing the IsFalse assertion failure

  4. Rimuovere la stringa "Errore" aggiunta nel passaggio 1. Eseguire nuovamente il test. I test verranno superati.

Test della versione di rilascio della libreria

Ora che tutti i test sono stati superati durante l'esecuzione della compilazione Debug della libreria, eseguire i test un tempo aggiuntivo rispetto alla versione di rilascio della libreria. Esistono infatti alcuni fattori, ad esempio le ottimizzazioni del compilatore, in grado di generare a volte comportamenti diversi tra la versione di debug e quella di rilascio.

Per testare la versione di rilascio, seguire questa procedura:

  1. Nella barra degli strumenti di Visual Studio modificare la configurazione di compilazione da Debug a Rilascio.

    Visual Studio toolbar with release build highlighted

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto StringLibrary e selezionare Compila dal menu di scelta rapida per ricompilare la libreria.

    StringLibrary context menu with build command

  3. Eseguire gli unit test scegliendo Test>Esegui tutti i test dalla barra dei menu. I test avranno esito positivo.

Esecuzione del debug dei test

Se si usa Visual Studio come IDE, è possibile usare lo stesso processo illustrato in Esercitazione: Eseguire il debug di un'applicazione console .NET usando Visual Studio per eseguire il debug del codice usando il progetto di unit test. Invece di avviare il progetto di app ShowCase, fare clic con il pulsante destro del mouse sul progetto StringLibraryTests e scegliere Debug test dal menu di scelta rapida.

Visual Studio avvia il progetto di test con il debugger collegato. L'esecuzione verrà arrestata in qualsiasi punto di interruzione aggiunto al progetto di test o al codice della libreria sottostante.

Risorse aggiuntive

Passaggi successivi

In questa esercitazione è stata testata una libreria di classi. È possibile rendere disponibile la libreria ad altri utenti pubblicandola in NuGet come pacchetto. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Se si pubblica una libreria come pacchetto NuGet, altri utenti possono installarla e usarla. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Non è necessario distribuire una libreria come pacchetto. Può essere incluso in un'app console che la usa. Per informazioni su come pubblicare un'app console, vedere l'esercitazione precedente in questa serie:

Questa esercitazione illustra come automatizzare gli unit test aggiungendo un progetto di test a una soluzione.

Prerequisiti

Creare un progetto di unit test

Gli unit test forniscono test software automatici durante le fasi di sviluppo e pubblicazione. MSTest è uno dei tre framework di test tra cui è possibile scegliere. Gli altri sono xUnit e nUnit.

  1. Avviare Visual Studio.

  2. Aprire la soluzione ClassLibraryProjects creata in Creare una libreria di classi .NET usando Visual Studio.

  3. Aggiungere alla soluzione un nuovo progetto di unit test denominato "StringLibraryTest".

    1. Fare clic con il pulsante destro del mouse sulla soluzione in Esplora soluzioni e selezionare Aggiungi>Nuovo progetto.

    2. Nella pagina Aggiungi un nuovo progetto immettere mstest nella casella di ricerca. Scegliere C# o Visual Basic dall'elenco Linguaggio e quindi scegliere Tutte le piattaforme dall'elenco Piattaforma.

    3. Scegliere il modello progetto di test MSTest e quindi scegliere Avanti.

    4. Nella pagina Configura il nuovo progetto immettere StringLibraryTest nella casella Nome progetto. Scegliere quindi Avanti.

    5. Nella pagina Informazioni aggiuntive selezionare .NET 6 (supporto a lungo termine) nella casella Framework. Scegli quindi Crea.

  4. Visual Studio crea il progetto e apre il file di classe nella finestra del codice con il codice seguente. Se il linguaggio che si vuole usare non viene visualizzato, modificare il selettore di linguaggio nella parte superiore della pagina.

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Sub TestSub()
    
            End Sub
        End Class
    End Namespace
    

    Il codice sorgente creato dal modello di unit test esegue le operazioni seguenti:

    Ogni metodo contrassegnato con [TestMethod] in una classe di test contrassegnata con [TestClass] viene eseguito automaticamente quando viene eseguito lo unit test.

Aggiungere un riferimento al progetto

Affinché il progetto di test funzioni con la classe StringLibrary, aggiungere un riferimento nel progetto StringLibraryTest al progetto StringLibrary.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo Dipendenze del progetto StringLibraryTest e selezionare Aggiungi riferimento al progetto dal menu di scelta rapida.

  2. Nella finestra di dialogo Gestione riferimenti espandere il nodo Progetti e selezionare la casella accanto a StringLibrary. L'aggiunta di un riferimento all'assembly StringLibrary consente al compilatore di trovare i metodi StringLibrary durante la compilazione del progetto StringLibraryTest.

  3. Seleziona OK.

Aggiungere ed eseguire metodi di unit test

Quando Visual Studio esegue uno unit test, esegue ogni metodo contrassegnato con l'attributo TestMethodAttribute in una classe contrassegnata con l'attributo TestClassAttribute. Un metodo di test termina quando viene trovato il primo errore o quando tutti i test contenuti nel metodo hanno avuto esito positivo.

I test più comuni chiamano i membri della classe Assert. Molti metodi assert includono almeno due parametri, uno dei quali corrisponde al risultato previsto del test, mentre l'altro corrisponde al risultato effettivo. Nella tabella seguente sono illustrati alcuni metodi chiamati più frequentemente della classe Assert:

Metodi Assert Funzione
Assert.AreEqual Verifica che due oggetti o valori siano uguali. L'asserzione ha esito negativo se i valori o gli oggetti non sono uguali.
Assert.AreSame Verifica che due variabili oggetto facciano riferimento allo stesso oggetto. Il metodo ha esito negativo se le variabili fanno riferimento a oggetti diversi.
Assert.IsFalse Verifica che una condizione sia false. Il metodo ha esito negativo se la condizione è true.
Assert.IsNotNull Verifica che un oggetto non sia null. Il metodo ha esito negativo se l'oggetto è null.

È anche possibile usare il metodo Assert.ThrowsException in un metodo di test per indicare il tipo di eccezione che dovrebbe generare. Il test ha esito negativo se l'eccezione specificata non viene generata.

Durante il test del metodo StringLibrary.StartsWithUpper, è possibile specificare alcune stringhe che iniziano con un carattere maiuscolo. In tal caso si prevede che il metodo restituisca true, quindi è possibile chiamare il metodo Assert.IsTrue. Analogamente, è possibile specificare alcune stringhe che iniziano con un valore diverso da un carattere maiuscolo. In tal caso si prevede che il metodo restituisca false, quindi è possibile chiamare il metodo Assert.IsFalse.

Poiché il metodo di libreria gestisce le stringhe, è anche necessario assicurarsi che gestisca correttamente una stringa vuota (String.Empty), una stringa valida senza caratteri e il cui Length è 0 e una stringa null che non è stata inizializzata. È possibile chiamare StartsWithUpper direttamente come metodo statico e passare un singolo argomento String. In alternativa, è possibile chiamare StartsWithUpper come metodo di estensione in una variabile di string assegnata a null.

Verranno definiti tre metodi, ognuno dei quali chiama un metodo Assert per ogni elemento in una matrice di stringhe. Verrà chiamato un overload del metodo che consente di specificare un messaggio di errore da visualizzare in caso di errore del test. Il messaggio identifica la stringa che ha causato l'errore.

Per creare i metodi di test:

  1. Nella finestra del codice UnitTest1.cs o UnitTest1.vb sostituire il codice con il codice seguente:

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using UtilityLibraries;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestStartsWithUpper()
            {
                // Tests that we expect to return true.
                string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsTrue(result,
                           string.Format("Expected for '{0}': true; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void TestDoesNotStartWithUpper()
            {
                // Tests that we expect to return false.
                string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " " };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word, result));
                }
            }
    
            [TestMethod]
            public void DirectCallWithNullOrEmpty()
            {
                // Tests that we expect to return false.
                string?[] words = { string.Empty, null };
                foreach (var word in words)
                {
                    bool result = StringLibrary.StartsWithUpper(word);
                    Assert.IsFalse(result,
                           string.Format("Expected for '{0}': false; Actual: {1}",
                                         word == null ? "<null>" : word, result));
                }
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    Imports UtilityLibraries
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Public Sub TestStartsWithUpper()
                ' Tests that we expect to return true.
                Dim words() As String = {"Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsTrue(result,
                           $"Expected for '{word}': true; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub TestDoesNotStartWithUpper()
                ' Tests that we expect to return false.
                Dim words() As String = {"alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " "}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsFalse(result,
                           $"Expected for '{word}': false; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub DirectCallWithNullOrEmpty()
                ' Tests that we expect to return false.
                Dim words() As String = {String.Empty, Nothing}
                For Each word In words
                    Dim result As Boolean = StringLibrary.StartsWithUpper(word)
                    Assert.IsFalse(result,
                           $"Expected for '{If(word Is Nothing, "<null>", word)}': false; Actual: {result}")
                Next
            End Sub
        End Class
    End Namespace
    

    Il test dei caratteri maiuscoli nel metodo TestStartsWithUpper include la lettera maiuscola greca alfa (U+0391) e la lettera maiuscola cirillico EM (U+041C). Il test dei caratteri minuscoli nel metodo TestDoesNotStartWithUpper include la lettera minuscola greca alfa (U+03B1) e la lettera minuscola cirillico Ghe (U+0433).

  2. Nella barra dei menu selezionare File>Salva UnitTest1.cs con nome o File>Salva UnitTest1.vb con nome. Nella finestra di dialogo Salva file con nome selezionare la freccia accanto al pulsante Salva e selezionare Salva con codifica.

    Visual Studio Save File As dialog

  3. Nella finestra di dialogo Conferma Salva con nome selezionare il pulsante per salvare il file.

  4. Nella finestra di dialogo Opzioni di salvataggio avanzate selezionare Unicode (UTF-8 con firma digitale) - Tabella codici 65001 dall'elenco a discesa Codifica e selezionare OK.

    Visual Studio Advanced Save Options dialog

    Se il salvataggio del codice sorgente come file con codifica UTF8 ha esito negativo, Visual Studio può salvarlo come file ASCII. In questo caso, il runtime non decodifica accuratamente i caratteri UTF8 all'esterno dell'intervallo ASCII e i risultati del test non saranno corretti.

  5. Nella barra dei menu selezionare Test>Esegui tutti i test. Se la finestra Esplora test non viene aperta, aprirla scegliendo Test>Esplora test. I tre test sono elencati nella sezione Test superati e nella sezione Riepilogo è riportato il risultato dell'esecuzione dei test.

    Test Explorer window with passing tests

Gestire gli errori di test

Se si esegue lo sviluppo basato su test (TDD), si scrivono prima i test e non riescono la prima volta che vengono eseguiti. Aggiungere quindi il codice all'app che rende il test riuscito. Per questa esercitazione è stato creato il test dopo aver scritto il codice dell'app convalidato, in modo da non aver visto l'esito negativo del test. Per verificare che un test non riesca quando si prevede che non riesca, aggiungere un valore non valido all'input di test.

  1. Modificare la matrice words del metodo TestDoesNotStartWithUpper per includere la stringa "Error". Non è necessario salvare il file perché Visual Studio salva i file aperti automaticamente quando viene creata una soluzione per eseguire i test.

    string[] words = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " };
    
    Dim words() As String = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " }
    
    
  2. Eseguire il test selezionando Test>Esegui tutti i test dalla barra dei menu. La finestra Esplora test indica che due test hanno avuto esito positivo e uno esito negativo.

    Test Explorer window with failing tests

  3. Selezionare il test non riuscito, TestDoesNotStartWith.

    Nella finestra Esplora test viene visualizzato il messaggio generato dal metodo Assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True". A causa dell'errore, non sono state testate stringhe nella matrice dopo il test di "Error".

    Test Explorer window showing the IsFalse assertion failure

  4. Rimuovere la stringa "Errore" aggiunta nel passaggio 1. Eseguire nuovamente il test. I test verranno superati.

Test della versione di rilascio della libreria

Ora che tutti i test sono stati superati durante l'esecuzione della compilazione Debug della libreria, eseguire i test un tempo aggiuntivo rispetto alla versione di rilascio della libreria. Esistono infatti alcuni fattori, ad esempio le ottimizzazioni del compilatore, in grado di generare a volte comportamenti diversi tra la versione di debug e quella di rilascio.

Per testare la versione di rilascio, seguire questa procedura:

  1. Nella barra degli strumenti di Visual Studio modificare la configurazione di compilazione da Debug a Rilascio.

    Visual Studio toolbar with release build highlighted

  2. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto StringLibrary e selezionare Compila dal menu di scelta rapida per ricompilare la libreria.

    StringLibrary context menu with build command

  3. Eseguire gli unit test scegliendo Test>Esegui tutti i test dalla barra dei menu. I test avranno esito positivo.

Esecuzione del debug dei test

Se si usa Visual Studio come IDE, è possibile usare lo stesso processo illustrato in Esercitazione: Eseguire il debug di un'applicazione console .NET usando Visual Studio per eseguire il debug del codice usando il progetto di unit test. Invece di avviare il progetto di app ShowCase, fare clic con il pulsante destro del mouse sul progetto StringLibraryTests e scegliere Debug test dal menu di scelta rapida.

Visual Studio avvia il progetto di test con il debugger collegato. L'esecuzione verrà arrestata in qualsiasi punto di interruzione aggiunto al progetto di test o al codice della libreria sottostante.

Risorse aggiuntive

Passaggi successivi

In questa esercitazione è stata testata una libreria di classi. È possibile rendere disponibile la libreria ad altri utenti pubblicandola in NuGet come pacchetto. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Se si pubblica una libreria come pacchetto NuGet, altri utenti possono installarla e usarla. Per informazioni su come farlo, seguire un'esercitazione su NuGet:

Non è necessario distribuire una libreria come pacchetto. Può essere incluso in un'app console che la usa. Per informazioni su come pubblicare un'app console, vedere l'esercitazione precedente in questa serie: