Delen via


Overzicht: Eenheidstests maken en uitvoeren voor beheerde code

In dit artikel wordt u stapsgewijs begeleid bij het maken, uitvoeren en aanpassen van een reeks eenheidstests met behulp van het Microsoft Unit Test Framework voor beheerde code en Visual Studio Test Explorer. U begint met een C#-project dat in ontwikkeling is, tests maakt waarmee de code wordt uitgevoerd, de tests worden uitgevoerd en de resultaten worden onderzocht. Vervolgens wijzigt u de projectcode en voert u de tests opnieuw uit. Als u een conceptueel overzicht van deze taken wilt voordat u deze stappen uitvoert, raadpleegt u basisbeginselen van eenheidstests. Als u automatisch tests wilt genereren op basis van bestaande code, kunt u Unit test methodestubs maken op basis van coderaadplegen.

Een project maken om te testen

  1. Open Visual Studio.

  2. Kies in het startvenster Een nieuw project maken.

  3. Zoek en selecteer de C# Console App projectsjabloon voor .NET en klik vervolgens op Volgende.

    Notitie

    Als u de console-app sjabloon niet ziet, kunt u deze installeren vanuit het Een nieuw project venster maken. In het Niet vinden wat u zoekt?-bericht kiest u de Meer hulpprogramma's en functies installeren link. Kies vervolgens in het installatieprogramma van Visual Studio de .NET-desktopontwikkeling workload.

  4. Noem het project Banken klik vervolgens op Volgende.

    Selecteer het aanbevolen doelframework of .NET 8 en selecteer daarna Maken.

    Het bankproject wordt gemaakt en weergegeven in Solution Explorer- met het Program.cs-bestand geopend in de code-editor.

    Notitie

    Als Program.cs niet is geopend in de editor, dubbelklikt u op het bestand Program.cs in Solution Explorer om het te openen.

  5. Vervang de inhoud van Program.cs door de volgende C#-code die een klasse definieert, BankAccount-:

    using System;
    
    namespace BankAccountNS
    {
        /// <summary>
        /// Bank account demo class.
        /// </summary>
        public class BankAccount
        {
            private readonly string m_customerName;
            private double m_balance;
    
            private BankAccount() { }
    
            public BankAccount(string customerName, double balance)
            {
                m_customerName = customerName;
                m_balance = balance;
            }
    
            public string CustomerName
            {
                get { return m_customerName; }
            }
    
            public double Balance
            {
                get { return m_balance; }
            }
    
            public void Debit(double amount)
            {
                if (amount > m_balance)
                {
                    throw new ArgumentOutOfRangeException("amount");
                }
    
                if (amount < 0)
                {
                    throw new ArgumentOutOfRangeException("amount");
                }
    
                m_balance += amount; // intentionally incorrect code
            }
    
            public void Credit(double amount)
            {
                if (amount < 0)
                {
                    throw new ArgumentOutOfRangeException("amount");
                }
    
                m_balance += amount;
            }
    
            public static void Main()
            {
                BankAccount ba = new BankAccount("Mr. Bryan Walton", 11.99);
    
                ba.Credit(5.77);
                ba.Debit(11.22);
                Console.WriteLine("Current balance is ${0}", ba.Balance);
            }
        }
    }
    
  6. Wijzig de naam van het bestand in BankAccount.cs door met de rechtermuisknop te klikken op en Hernoemen te kiezen in Solution Explorer.

  7. Klik in het menu Build op Build Solution (of druk op Ctrl + Shift + B).

U hebt nu een project met methoden die u kunt testen. In dit artikel richten de tests zich op de methode Debit. De Debit methode wordt aangeroepen wanneer geld uit een rekening wordt ingetrokken.

Een eenheidstestproject maken

  1. Selecteer in het menu Bestand de optie >Nieuw project toevoegen.

    Suggestie

    U kunt ook met de rechtermuisknop op de oplossing klikken in Solution Explorer- en >Nieuw project toevoegenkiezen.

  2. Typ test in het zoekvak, selecteer C# als taal en selecteer vervolgens de C# MSTest Test Project voor .NET-sjabloon en klik vervolgens op Volgende.

    Notitie

    In Visual Studio 2019 versie 16.9 is de MSTest-projectsjabloon Eenheidstestproject.

  3. Geef het project de naam BankTests en klik op Volgende.

  4. Selecteer het aanbevolen doelframework of .NET 8 en selecteer daarna Maken.

    Vanaf Visual Studio 2022 versie 17.10 kunt u ook een testrunner selecteren. Voor de testloper kunt u kiezen voor VSTest of MSTest. Voor meer informatie over het verschil tussen testrunners, zie vergelijking van Microsoft.Testing.Platform en VSTest.

    Het project BankTests wordt toegevoegd aan de oplossing Bank.

  5. Voeg in het project BankTests een verwijzing toe naar het project Bank.

    Selecteer in Solution ExplorerAfhankelijkheden onder het project BankTests en kies vervolgens Verwijzing toevoegen (of Projectverwijzing toevoegen) in het snelmenu.

  6. In het dialoogvenster Reference Manager, vouw Projectsuit, selecteer Solutionen vink vervolgens het item Bank aan.

  7. Kies OK-.

De testklasse maken

Maak een testklasse om de BankAccount-klasse te controleren. U kunt het UnitTest1.cs-bestand gebruiken dat is gegenereerd door de projectsjabloon, maar geef het bestand en de klasse meer beschrijvende namen.

De naam van een bestand en klasse wijzigen

  1. Als u de naam van het bestand wilt wijzigen, selecteert u in Solution Explorerhet UnitTest1.cs-bestand in het project BankTests. Kies in het contextmenu Naam wijzigen (of druk op F2) en geef het bestand de naam BankAccountTests.cs.

  2. Als u de naam van de klasse wilt wijzigen, plaatst u de cursor op UnitTest1 in de code-editor, klikt u met de rechtermuisknop en kiest u Naam wijzigen van (of drukt u op F2). Typ BankAccountTests en druk op Enter.

Het bestand BankAccountTests.cs bevat nu de volgende code:

// The 'using' statement for Test Tools is in GlobalUsings.cs
// using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BankTests
{
    [TestClass]
    public class BankAccountTests
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
}

Een using-instructie toevoegen

Voeg een using instructie toe aan de testklasse om toegang te krijgen tot het geteste project zonder volledig gekwalificeerde namen te gebruiken. Voeg boven aan het klassebestand het volgende toe:

using BankAccountNS;

Testklassevereisten

De minimale vereisten voor een testklasse zijn:

  • Het kenmerk [TestClass] is vereist voor elke klasse die eenheidstestmethoden bevat die u wilt uitvoeren in Test Explorer.

  • Elke testmethode die u testverkenner wilt herkennen, moet het kenmerk [TestMethod] hebben.

U kunt andere klassen hebben in een eenheidstestproject dat niet het kenmerk [TestClass] heeft en u kunt andere methoden hebben in testklassen die niet over het kenmerk [TestMethod] beschikken. U kunt deze andere klassen en methoden aanroepen vanuit uw testmethoden.

De eerste testmethode maken

In deze procedure schrijft u testmethoden voor eenheden om het gedrag van de Debit methode van de BankAccount-klasse te controleren.

Er zijn ten minste drie gedragingen die moeten worden gecontroleerd:

  • De methode genereert een ArgumentOutOfRangeException als het debitbedrag groter is dan het saldo.

  • De methode genereert een ArgumentOutOfRangeException als het debetbedrag kleiner is dan nul.

  • Als het debetbedrag geldig is, trekt de methode het debitbedrag af van het rekeningsaldo.

Suggestie

U kunt de standaardmethode TestMethod1 verwijderen, omdat u deze niet in dit scenario gebruikt.

Een testmethode maken

Met de eerste test wordt gecontroleerd of een geldig bedrag (dat wil gezegd een bedrag dat kleiner is dan het rekeningsaldo en groter dan nul) het juiste bedrag van de rekening intrekt. Voeg de volgende methode toe aan die BankAccountTests klasse:

[TestMethod]
public void Debit_WithValidAmount_UpdatesBalance()
{
    // Arrange
    double beginningBalance = 11.99;
    double debitAmount = 4.55;
    double expected = 7.44;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // Act
    account.Debit(debitAmount);

    // Assert
    double actual = account.Balance;
    Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly");
}

De methode is eenvoudig: er wordt een nieuw BankAccount-object ingesteld met een beginsaldo en vervolgens een geldig bedrag ingetrokken. Er wordt gebruikgemaakt van de methode Assert.AreEqual om te controleren of het eindsaldo is zoals verwacht. Methoden zoals Assert.AreEqual, Assert.IsTrueen andere methoden worden vaak gebruikt bij het testen van eenheden. Voor meer conceptuele informatie over het schrijven van een unittest, zie Uw tests schrijven.

Vereisten voor testmethode

Een testmethode moet voldoen aan de volgende vereisten:

  • Het is versierd met het [TestMethod] kenmerk.

  • Het geeft voidterug.

  • Het mag geen parameters hebben.

De test bouwen en uitvoeren

  1. Kies in het menu BuildBuild Solution (of druk op Ctrl + Shift + B).

  2. Als Test Explorer niet is geopend, opent u deze door >testverkenner (of Test>Windows>Test Explorer) te kiezen in de bovenste menubalk (of druk op Ctrl + E, T).

  3. Kies Alles uitvoeren om de test uit te voeren (of druk op Ctrl + R, V).

    Terwijl de test wordt uitgevoerd, wordt de statusbalk boven aan het venster Test Explorer geanimeerd. Aan het einde van de testuitvoering wordt de balk groen als alle testmethoden slagen of rood als een van de tests mislukt.

    In dit geval mislukt de test.

  4. Selecteer de methode in Test Explorer om de details onder aan het venster weer te geven.

Uw code herstellen en uw tests opnieuw uitvoeren

Het testresultaat bevat een bericht waarin de fout wordt beschreven. Mogelijk moet u inzoomen om dit bericht te zien. Voor de AreEqual-methode wordt in het bericht weergegeven wat er is verwacht en wat er daadwerkelijk is ontvangen. U had verwacht dat het saldo afneemt, maar in plaats daarvan verhoogd met het bedrag van de intrekking.

De eenheidstest heeft een fout ontdekt: het bedrag van de opname wordt toegevoegd aan het rekeningsaldo wanneer het moet worden afgetrokken .

De fout corrigeren

Vervang de regel in het BankAccount.cs bestand om de fout te corrigeren:

m_balance += amount;

met:

m_balance -= amount;

De test opnieuw uitvoeren

Kies in Test ExplorerAlle uitvoeren om de test opnieuw uit te voeren (of druk op Ctrl + R, V). De rode/groene balk wordt groen om aan te geven dat de test is geslaagd.

Test Explorer in Visual Studio 2019 met geslaagde test

Test Explorer in Visual Studio 2019 met geslaagde test

Eenheidstests gebruiken om uw code te verbeteren

In deze sectie wordt beschreven hoe u met een iteratief proces van analyse, moduletestontwikkeling en herstructurering uw productiecode robuuster en effectiever kunt maken.

De problemen analyseren

U hebt een testmethode gemaakt om te bevestigen dat een geldig bedrag correct wordt afgetrokken in de methode Debit. Controleer nu of de methode een ArgumentOutOfRangeException genereert als het debetbedrag een van de volgende is:

  • groter dan het saldo, of
  • kleiner dan nul.

Nieuwe testmethoden maken en uitvoeren

Maak een testmethode om het juiste gedrag te controleren wanneer het debitbedrag kleiner is dan nul:

[TestMethod]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
    // Arrange
    double beginningBalance = 11.99;
    double debitAmount = -100.00;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // Act and assert
    Assert.ThrowsException<System.ArgumentOutOfRangeException>(() => account.Debit(debitAmount));
}

Gebruik de methode ThrowsException om te bevestigen dat de juiste uitzondering is gegenereerd. Deze methode zorgt ervoor dat de test mislukt, tenzij er een ArgumentOutOfRangeException wordt gegenereerd. Als u de methode onder test tijdelijk wijzigt om een algemenere ApplicationException te gooien wanneer het debitbedrag kleiner is dan nul, gedraagt de test zich correct, dat wil gezegd dat deze mislukt.

Voer de volgende stappen uit om de case te testen wanneer het ingetrokken bedrag groter is dan het saldo:

  1. Maak een nieuwe testmethode met de naam Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange.

  2. Kopieer de hoofdtekst van de methode van Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange naar de nieuwe methode.

  3. Stel de debitAmount in op een getal dat groter is dan het saldo.

Voer de twee tests uit en controleer of ze zijn geslaagd.

Doorgaan met de analyse

De geteste methode kan verder worden verbeterd. Met de huidige implementatie weten we niet welke voorwaarde (amount > m_balance of amount < 0) heeft geleid tot de uitzondering die tijdens de test wordt gegenereerd. We weten gewoon dat er een ArgumentOutOfRangeException ergens in de methode is gegooid. Het zou beter zijn als we kunnen zien welke voorwaarde in BankAccount.Debit ervoor zorgde dat de uitzondering werd gegenereerd (amount > m_balance of amount < 0), zodat we er zeker van kunnen zijn dat onze methode de argumenten correct controleert.

Bekijk opnieuw de methode die wordt getest (BankAccount.Debit) en u ziet dat beide voorwaardelijke instructies een ArgumentOutOfRangeException constructor gebruiken die alleen de naam van het argument als parameter krijgt:

throw new ArgumentOutOfRangeException("amount");

Er is een constructor die u kunt gebruiken voor veel uitgebreidere informatie: ArgumentOutOfRangeException(String, Object, String) bevat de naam van het argument, de argumentwaarde en een door de gebruiker gedefinieerd bericht. U kunt de methode onder test herstructureren om deze constructor te gebruiken. Nog beter, u kunt publiek beschikbare typeleden gebruiken om fouten aan te duiden.

De code onder test herstructureren

Definieer eerst twee constanten voor de foutberichten in het klassebereik. Plaats de definities in de klasse onder test BankAccount:

public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
public const string DebitAmountLessThanZeroMessage = "Debit amount is less than zero";

Wijzig vervolgens de twee voorwaardelijke instructies in de methode Debit:

if (amount > m_balance)
{
    throw new System.ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
}

if (amount < 0)
{
    throw new System.ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
}

De testmethoden herstructureren

Herstructureer de testmethoden door de aanroep naar Assert.ThrowsExceptionte verwijderen. Omhul de aanroep naar Debit() in een try/catch-blok, vang de specifieke uitzondering die wordt verwacht, en verifieer het bijbehorende bericht. De methode Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.Contains biedt de mogelijkheid om twee tekenreeksen te vergelijken.

De Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange ziet er nu als volgt uit:

[TestMethod]
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()
{
    // Arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // Act
    try
    {
        account.Debit(debitAmount);
    }
    catch (System.ArgumentOutOfRangeException e)
    {
        // Assert
        StringAssert.Contains(e.Message, BankAccount.DebitAmountExceedsBalanceMessage);
    }
}

Opnieuw testen, herschrijven en opnieuwanalyze

Op dit moment verwerkt de testmethode niet alle gevallen die nodig zijn. Als de methode die wordt getest, de Debit methode, geen ArgumentOutOfRangeException zou gooien wanneer de debitAmount groter is dan het saldo of kleiner dan nul, zou de testmethode slagen. Dit scenario is niet goed omdat u wilt dat de testmethode mislukt als er geen uitzondering wordt gegenereerd.

Dit resultaat is een fout in de testmethode. Als u het probleem wilt oplossen, voegt u een Assert.Fail assert toe aan het einde van de testmethode om de case af te handelen waarbij er geen uitzondering wordt gegenereerd.

Het opnieuw uitvoeren van de test laat zien dat de test nu mislukt als de juiste uitzondering wordt opgevangen. De catch-blok onderschept de uitzondering, maar de methode blijft uitvoeren en mislukt bij de nieuwe Assert.Fail assert. U kunt dit probleem oplossen door een return instructie toe te voegen na de StringAssert in het catch blok. Als u de test opnieuw uitvoert, wordt bevestigd dat u dit probleem hebt opgelost. De definitieve versie van de Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange ziet er als volgt uit:

[TestMethod]
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()
{
    // Arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // Act
    try
    {
        account.Debit(debitAmount);
    }
    catch (System.ArgumentOutOfRangeException e)
    {
        // Assert
        StringAssert.Contains(e.Message, BankAccount.DebitAmountExceedsBalanceMessage);
        return;
    }

    Assert.Fail("The expected exception was not thrown.");
}

Conclusie

De verbeteringen in de testcode hebben geleid tot robuustere en informatieve testmethoden. Maar belangrijker nog, ze hebben ook de code onder test verbeterd.

Suggestie

In dit scenario wordt gebruikgemaakt van het Microsoft-eenheidstestframework voor beheerde code. Test Explorer- kan ook tests uitvoeren vanuit testframeworks van derden met adapters voor Test Explorer-. Zie Testframeworks van derden installerenvoor meer informatie.

Zie VSTest.Console.exe opdrachtregeloptiesvoor meer informatie over het uitvoeren van tests vanaf een opdrachtregel.