Oefening: eenheidstests toevoegen aan uw toepassing

Voltooid

In deze les voegen we eenheidstests toe aan de geautomatiseerde build die we hebben gemaakt met Microsoft Azure Pipelines. Regressiefouten kruipen in de code van uw team en breken de filterfunctionaliteit van het leaderboard af. In het bijzonder wordt de verkeerde gamemodus weergegeven.

In de volgende afbeelding ziet u het probleem. Wanneer een gebruiker 'Milky Way' selecteert om alleen scores van die gamekaart weer te geven, krijgen ze resultaten van andere gamekaarten, zoals Andromeda.

Een schermopname van het leaderboard met onjuiste resultaten: Andromeda galaxy scores worden weergegeven in de Milky Way galaxy listing.

Het team wil de fout ondervangen voordat het de testers bereikt. Eenheidstests zijn een uitstekende manier om automatisch te testen op regressiefouten.

Door de eenheidstests op dit moment in het proces toe te voegen, krijgt het team een voorsprong bij het verbeteren van de Space Game-web-app . De toepassing maakt gebruik van een documentdatabase voor het opslaan van hoge scores en spelerprofielen. Op dit moment worden lokale testgegevens gebruikt. Later zijn ze van plan om de app te verbinden met een livedatabase.

Er zijn veel moduletestframeworks beschikbaar voor C#-toepassingen. We gebruiken NUnit omdat het populair is bij de community.

Hier volgt de eenheidstest waarmee u werkt:

[TestCase("Milky Way")]
[TestCase("Andromeda")]
[TestCase("Pinwheel")]
[TestCase("NGC 1300")]
[TestCase("Messier 82")]
public void FetchOnlyRequestedGameRegion(string gameRegion)
{
    const int PAGE = 0; // take the first page of results
    const int MAX_RESULTS = 10; // sample up to 10 results

    // Form the query predicate.
    // This expression selects all scores for the provided game region.
    Expression<Func<Score, bool>> queryPredicate = score => (score.GameRegion == gameRegion);

    // Fetch the scores.
    Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
        queryPredicate, // the predicate defined above
        score => 1, // we don't care about the order
        PAGE,
        MAX_RESULTS
    );
    IEnumerable<Score> scores = scoresTask.Result;

    // Verify that each score's game region matches the provided game region.
    Assert.That(scores, Is.All.Matches<Score>(score => score.GameRegion == gameRegion));
}

U kunt het leaderboard filteren op elke combinatie van speltype en spelkaart.

Deze test voert een query uit op het leaderboard voor hoge scores en controleert of elk resultaat overeenkomt met de opgegeven gamekaart.

In een NUnit-testmethode TestCase kunt u inlinegegevens gebruiken om die methode te testen. Hier roept NUnit de FetchOnlyRequestedGameRegion eenheidstestmethode als volgt aan:

FetchOnlyRequestedGameRegion("Milky Way");
FetchOnlyRequestedGameRegion("Andromeda");
FetchOnlyRequestedGameRegion("Pinwheel");
FetchOnlyRequestedGameRegion("NGC 1300");
FetchOnlyRequestedGameRegion("Messier 82");

Let op de aanroep van de Assert.That methode aan het einde van de test. Een bewering is een voorwaarde of instructie die u verklaart waar te zijn. Als de voorwaarde onwaar blijkt te zijn, kan dit duiden op een fout in uw code. NUnit voert elke testmethode uit met behulp van de inlinegegevens die u opgeeft en registreert het resultaat als een geslaagde of mislukte test.

Veel frameworks voor eenheidstests bieden verificatiemethoden die lijken op natuurlijke taal. Met deze methoden kunt u tests gemakkelijk lezen en helpen u de tests toe te wijzen aan de vereisten van de toepassing.

Bekijk de bewering in dit voorbeeld:

Assert.That(scores, Is.All.Matches<Score>(score => score.GameRegion == gameRegion));

U kunt deze regel lezen als:

Bevestig dat de gameregio van elke geretourneerde score overeenkomt met de opgegeven gameregio.

Dit is het proces dat u moet volgen:

  1. Haal een vertakking op uit de GitHub-opslagplaats die de eenheidstests bevat.
  2. Voer de tests lokaal uit om te controleren of ze zijn geslaagd.
  3. Voeg taken toe aan uw pijplijnconfiguratie om de tests uit te voeren en de resultaten te verzamelen.
  4. Push de vertakking naar uw GitHub-opslagplaats.
  5. Bekijk hoe uw Azure Pipelines-project de toepassing automatisch bouwt en de tests uitvoert.

De branch ophalen vanuit GitHub

Hier haalt u de unit-tests vertakking op van GitHub en checkt u deze vertakking uit of schakelt u over naar die vertakking.

Deze vertakking bevat het Space Game-project waarmee u hebt gewerkt in de vorige modules en een Azure Pipelines-configuratie om mee te beginnen.

  1. Open in Visual Studio Code de geïntegreerde terminal.

  2. Voer de volgende git opdrachten uit om een vertakking op te halen met de naam unit-tests uit de Microsoft-opslagplaats en schakel vervolgens over naar die vertakking.

    git fetch upstream unit-tests
    git checkout -B unit-tests upstream/unit-tests
    

    Met de indeling van deze opdracht kunt u starterscode ophalen uit de Microsoft GitHub-opslagplaats, ook wel bekend als upstream. Binnenkort pusht u deze vertakking naar uw GitHub-opslagplaats, ook wel bekend als origin.

  3. Als optionele stap opent u het azure-pipelines.yml-bestand in Visual Studio Code en maakt u vertrouwd met de eerste configuratie. De configuratie lijkt op de basisconfiguratie die u hebt gemaakt in de module Een build-pipeline maken met Azure Pipelines. Hiermee wordt alleen de releaseconfiguratie van de toepassing geconfigureerd.

De tests lokaal uitvoeren

Het is een goed idee om alle tests lokaal uit te voeren voordat u tests naar de pijplijn verzendt. Dat gaat u hier doen.

  1. Open in Visual Studio Code de geïntegreerde terminal.

  2. Voer deze opdracht uit dotnet build om elk project in de oplossing te bouwen.

    dotnet build --configuration Release
    
  3. Voer de volgende dotnet test opdracht uit om de eenheidstests uit te voeren:

    dotnet test --configuration Release --no-build
    

    De --no-build vlag geeft aan dat het project niet moet worden gebouwd voordat het wordt uitgevoerd. U hoeft het project niet te bouwen omdat u het in de vorige stap hebt gebouwd.

    U ziet dat alle vijf de tests slagen.

    Starting test execution, please wait...
    A total of 1 test files matched the specified pattern.
    
    Passed!  - Failed:     0, Passed:     5, Skipped:     0, Total:     5, Duration: 57 ms
    

    In dit voorbeeld hebben de tests minder dan één seconde geduurd om uit te voeren.

    U ziet dat er vijf totaaltests zijn. Hoewel we slechts één testmethode hebben gedefinieerd, FetchOnlyRequestedGameRegionwordt die test vijf keer uitgevoerd, één keer voor elke gamekaart zoals opgegeven in de TestCase inlinegegevens.

  4. Voer de tests een tweede keer uit. Geef deze keer de --logger optie op om de resultaten naar een logboekbestand te schrijven.

    dotnet test Tailspin.SpaceGame.Web.Tests --configuration Release --no-build --logger trx
    

    U ziet in de uitvoer dat er een TRX-bestand wordt gemaakt in de map TestResults .

    Een TRX-bestand is een XML-document dat de resultaten van een testuitvoering bevat. Het is een populaire indeling voor testresultaten, omdat Visual Studio en andere hulpprogramma's u kunnen helpen de resultaten te visualiseren.

    Later ziet u hoe u met Azure Pipelines uw testresultaten kunt visualiseren en bijhouden terwijl ze door de pijplijn worden uitgevoerd.

    Notitie

    TRX-bestanden zijn niet bedoeld om te worden opgenomen in broncodebeheer. Met een .gitignore-bestand kunt u opgeven welke tijdelijke en andere bestanden u door Git wilt negeren. Het .gitignore-bestand van het project is al ingesteld om alles in de map TestResults te negeren.

  5. Als optionele stap opent u in Visual Studio Code het bestand DocumentDBRepository_GetItemsAsyncShould.cs uit de map Tailspin.SpaceGame.Web.Tests en bekijkt u de testcode. Zelfs als u niet specifiek geïnteresseerd bent in het bouwen van .NET-apps, vindt u mogelijk de testcode nuttig omdat deze lijkt op code die u in andere eenheidstestframeworks ziet.

Taken toevoegen aan uw pijplijnconfiguratie

Hier configureert u de build-pijplijn om uw eenheidstests uit te voeren en de resultaten te verzamelen.

  1. Wijzig in Visual Studio Code azure-pipelines.yml als volgt:

    trigger:
    - '*'
    
    pool:
      vmImage: 'ubuntu-20.04'
      demands:
      - npm
    
    variables:
      buildConfiguration: 'Release'
      wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
      dotnetSdkVersion: '6.x'
    
    steps:
    - task: UseDotNet@2
      displayName: 'Use .NET SDK $(dotnetSdkVersion)'
      inputs:
        version: '$(dotnetSdkVersion)'
    
    - task: Npm@1
      displayName: 'Run npm install'
      inputs:
        verbose: false
    
    - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
      displayName: 'Compile Sass assets'
    
    - task: gulp@1
      displayName: 'Run gulp tasks'
    
    - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
      displayName: 'Write build info'
      workingDirectory: $(wwwrootDir)
    
    - task: DotNetCoreCLI@2
      displayName: 'Restore project dependencies'
      inputs:
        command: 'restore'
        projects: '**/*.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Build the project - $(buildConfiguration)'
      inputs:
        command: 'build'
        arguments: '--no-restore --configuration $(buildConfiguration)'
        projects: '**/*.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Run unit tests - $(buildConfiguration)'
      inputs:
        command: 'test'
        arguments: '--no-build --configuration $(buildConfiguration)'
        publishTestResults: true
        projects: '**/*.Tests.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Publish the project - $(buildConfiguration)'
      inputs:
        command: 'publish'
        projects: '**/*.csproj'
        publishWebProjects: false
        arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
        zipAfterPublish: true
    
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      condition: succeeded()
    

    In deze versie wordt deze DotNetCoreCLI@2 buildtaak geïntroduceerd.

    - task: DotNetCoreCLI@2
      displayName: 'Run unit tests - $(buildConfiguration)'
      inputs:
        command: 'test'
        arguments: '--no-build --configuration $(buildConfiguration)'
        publishTestResults: true
        projects: '**/*.Tests.csproj'
    

    Met deze build-taak wordt de dotnet test opdracht uitgevoerd.

    U ziet dat met deze taak niet het --logger trx argument wordt opgegeven dat u hebt gebruikt bij het handmatig uitvoeren van de tests. Het publishTestResults argument voegt dat voor u toe. Dit argument vertelt de pijplijn om het TRX-bestand te genereren naar een tijdelijke map die toegankelijk is via de $(Agent.TempDirectory) ingebouwde variabele. Ook worden de taakresultaten naar de pijplijn gepubliceerd.

    Het projects argument geeft alle C#-projecten op die overeenkomen met **/*. Tests.csproj." Het deel ** komt overeen met alle mappen en de *. Het onderdeel Tests.csproj komt overeen met alle projecten waarvan de bestandsnaam eindigt op '. Tests.csproj." De unit-tests vertakking bevat slechts één eenheidstestproject, Tailspin.SpaceGame.Web.Tests.csproj. Door een patroon op te geven, kunt u meer testprojecten uitvoeren zonder dat u de buildconfiguratie hoeft te wijzigen.

De vertakking naar GitHub pushen

Hier pusht u uw wijzigingen naar GitHub en ziet u de pijplijnuitvoering. Zoals u weet, bevindt u zich momenteel in de vertakking unit-tests.

  1. Voeg in de geïntegreerde terminal azure-pipelines.yml toe aan de index, voer de wijzigingen door en push de vertakking naar GitHub.

    git add azure-pipelines.yml
    git commit -m "Run and publish unit tests"
    git push origin unit-tests
    

Bekijk hoe Azure Pipelines de tests uitvoert

Hier ziet u de tests die worden uitgevoerd in de pijplijn en visualiseert u vervolgens de resultaten van Microsoft Azure-testplannen. Azure Test Plans biedt alle hulpprogramma's die u nodig hebt om uw toepassingen te testen. U kunt handmatige testplannen maken en uitvoeren, geautomatiseerde tests genereren en feedback verzamelen van belanghebbenden.

  1. Traceer in Azure Pipelines de build via elk van de stappen.

    U ziet dat de eenheidstests uitvoeren- Releasetaak de eenheidstests uitvoert, net zoals u handmatig hebt uitgevoerd vanaf de opdrachtregel.

    Een schermopname van Azure Pipelines met console-uitvoer van het uitvoeren van eenheidstests.

  2. Ga terug naar de pijplijnsamenvatting.

  3. Naar het tabblad Tests gaan.

    U ziet een samenvatting van de testuitvoering. Alle vijf de tests zijn geslaagd.

    Een schermopname van Azure Pipelines met het tabblad Tests met 5 totaal uitgevoerde tests en 100 procent doorgegeven.

  4. Selecteer In Azure DevOps testplannen en selecteer vervolgens Runs.

    Een schermopname van het navigatiemenu van Azure DevOps met de sectie Testplannen en het tabblad Runs gemarkeerd.

    U ziet de meest recente testuitvoeringen, inclusief de test die u zojuist hebt uitgevoerd.

  5. Dubbelklik op de meest recente testuitvoering.

    U ziet een samenvatting van de resultaten.

    Een schermopname van de azure DevOps-testresultatenoverzicht met vijf geslaagde tests.

    In dit voorbeeld zijn alle vijf de tests geslaagd. Als er tests zijn mislukt, kunt u naar de build-taak gaan voor meer informatie.

    U kunt het TRX-bestand ook downloaden om het te onderzoeken via Visual Studio of een ander visualisatieprogramma.

Hoewel u slechts één test hebt toegevoegd, is het een goed begin en wordt het onmiddellijke probleem opgelost. Het team heeft nu een plek om meer tests toe te voegen en ze uit te voeren naarmate ze hun proces verbeteren.

Uw vertakking samenvoegen in de hoofdmap

In een praktijkscenario, als u tevreden bent met de resultaten, kunt u de unit-tests vertakking samenvoegen naar main, maar voor kortheid slaan we dat proces voorlopig over.