Övning – Lägga till enhetstester i ditt program

Slutförd

I den här lektionen lägger vi till enhetstester i den automatiserade versionen som vi skapade med Microsoft Azure Pipelines. Regressionsbuggar kryper in i teamets kod och bryter rankningslistans filtreringsfunktioner. Mer specifikt fortsätter fel spelläge att visas.

Följande bild illustrerar problemet. När en användare väljer "Vintergatan" för att endast visa poäng från den spelkartan får de resultat från andra spelkartor, till exempel Andromeda.

A screenshot of the leaderboard showing incorrect results: Andromeda galaxy scores show in the Milky Way galaxy listing.

Teamet vill fånga upp felet innan det når testarna. Enhetstester är ett bra sätt att automatiskt testa för regressionsbuggar.

Genom att lägga till enhetstesterna vid den här tidpunkten i processen får teamet ett försprång när de förbättrar webbappen Space Game . Programmet använder en dokumentdatabas för att lagra höga poäng och spelarprofiler. Just nu använder den lokala testdata. Senare planerar de att ansluta appen till en livedatabas.

Många enhetstestramverk är tillgängliga för C#-program. Vi använder NUnit eftersom det är populärt i communityn.

Här är enhetstestet som du arbetar med:

[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));
}

Du kan filtrera rankningslistan efter valfri kombination av speltyp och spelkarta.

Det här testet frågar rankningslistan efter höga poäng och verifierar att varje resultat matchar den angivna spelkartan.

I en NUnit-testmetod TestCase tillhandahåller infogade data att använda för att testa den metoden. Här anropar FetchOnlyRequestedGameRegion NUnit enhetstestmetoden enligt följande:

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

Observera anropet Assert.That till metoden i slutet av testet. Ett påstående är ett villkor eller en instruktion som du deklarerar vara sant. Om villkoret visar sig vara falskt kan det tyda på en bugg i koden. NUnit kör varje testmetod med hjälp av de infogade data som du anger och registrerar resultatet som ett godkänt eller misslyckat test.

Många enhetstestramverk tillhandahåller verifieringsmetoder som liknar naturligt språk. De här metoderna gör det enkelt att läsa och hjälpa dig att mappa testerna till programmets krav.

Överväg försäkran i det här exemplet:

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

Du kan läsa den här raden som:

Bekräfta att spelregionen för varje returnerad poäng matchar den angivna spelregionen.

Här är processen att följa:

  1. Hämta en gren från GitHub-lagringsplatsen som innehåller enhetstesterna.
  2. Kör testerna lokalt för att verifiera att de har godkänts.
  3. Lägg till uppgifter i pipelinekonfigurationen för att köra testerna och samla in resultaten.
  4. Skicka grenen till din GitHub-lagringsplats.
  5. Se hur ditt Azure Pipelines-projekt automatiskt skapar programmet och kör testerna.

Hämta grenen från GitHub

Här hämtar du grenen unit-tests från GitHub och checkar ut eller växlar till den grenen.

Den här grenen innehåller space game-projektet som du arbetade med i de föregående modulerna och en Azure Pipelines-konfiguration till att börja med.

  1. Öppna den integrerade terminalen i Visual Studio Code.

  2. Kör följande git kommandon för att hämta en gren med namnet unit-tests från Microsoft-lagringsplatsen och växla sedan till den grenen.

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

    Med formatet för det här kommandot kan du hämta startkod från Microsoft GitHub-lagringsplatsen, som upstreamkallas . Snart skickar du den här grenen till din GitHub-lagringsplats, som originkallas .

  3. Som ett valfritt steg öppnar du filen azure-pipelines.yml i Visual Studio Code och bekanta dig med den inledande konfigurationen. Konfigurationen liknar den grundläggande konfiguration som du skapade i modulen Skapa en bygg-pipeline med Azure-pipelines. Den skapar endast programmets versionskonfiguration.

Köra testerna lokalt

Det är en bra idé att köra alla tester lokalt innan du skickar några tester till pipelinen. Det ska vi göra nu.

  1. Öppna den integrerade terminalen i Visual Studio Code.

  2. Kör dotnet build för att skapa varje projekt i lösningen.

    dotnet build --configuration Release
    
  3. Kör följande dotnet test kommando för att köra enhetstesterna:

    dotnet test --configuration Release --no-build
    

    Flaggan --no-build anger att projektet inte ska skapas innan det körs. Du behöver inte skapa projektet eftersom du skapade det i föregående steg.

    Du bör se att alla fem testerna godkänns.

    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
    

    I det här exemplet tog testerna mindre än en sekund att köra.

    Observera att det fanns fem totalt antal tester. Även om vi bara definierade en testmetod FetchOnlyRequestedGameRegionkörs det testet fem gånger, en gång för varje spelkarta enligt vad som anges i infogade TestCase data.

  4. Kör testerna en andra gång. Den här gången anger du --logger alternativet för att skriva resultatet till en loggfil.

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

    Du ser från utdata att en TRX-fil skapas i katalogen TestResults .

    En TRX-fil är ett XML-dokument som innehåller resultatet av en testkörning. Det är ett populärt format för testresultat eftersom Visual Studio och andra verktyg kan hjälpa dig att visualisera resultaten.

    Senare ser du hur Azure Pipelines kan hjälpa dig att visualisera och spåra dina testresultat när de körs via pipelinen.

    Kommentar

    TRX-filer är inte avsedda att ingå i källkontrollen. Med en .gitignore-fil kan du ange vilka temporära filer och andra filer som du vill att Git ska ignorera. Projektets .gitignore-fil har redan konfigurerats för att ignorera allt i katalogen TestResults.

  5. Som ett valfritt steg öppnar du filen DocumentDBRepository_GetItemsAsyncShould.cs i Visual Studio Code från mappen Tailspin.SpaceGame.Web.Tests och undersöker testkoden. Även om du inte är intresserad av att skapa .NET-appar specifikt kan testkoden vara användbar eftersom den liknar kod som du kanske ser i andra enhetstestramverk.

Lägga till uppgifter i pipelinekonfigurationen

Här konfigurerar du bygg-pipelinen för att köra enhetstesterna och samla in resultaten.

  1. Ändra azure-pipelines.yml enligt följande i Visual Studio Code:

    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()
    

    Den här versionen introducerar den här DotNetCoreCLI@2 bygguppgiften.

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

    Den här bygguppgiften dotnet test kör kommandot .

    Observera att den här uppgiften inte anger det --logger trx argument som du använde när du körde testerna manuellt. Argumentet publishTestResults lägger till det åt dig. Det här argumentet talar om för pipelinen att generera TRX-filen till en tillfällig katalog som är tillgänglig via den $(Agent.TempDirectory) inbyggda variabeln. Den publicerar också aktivitetsresultatet till pipelinen.

    Argumentet projects anger alla C#-projekt som matchar "**/*. Tests.csproj." Delen "**" matchar alla kataloger och "*. Tests.csproj" -delen matchar alla projekt vars filnamn slutar med ". Tests.csproj." Grenen unit-tests innehåller bara ett enhetstestprojekt, Tailspin.SpaceGame.Web.Tests.csproj. Genom att ange ett mönster kan du köra fler testprojekt utan att behöva ändra byggkonfigurationen.

Skicka grenen till GitHub

Här skickar du ändringarna till GitHub och ser pipelinekörningen. Kom ihåg att du för närvarande är på grenen unit-tests.

  1. I den integrerade terminalen lägger du till azure-pipelines.yml i indexet, checkar in ändringarna och push-överför grenen till GitHub.

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

Se hur Azure Pipelines kör testerna

Här ser du testerna som körs i pipelinen och visualiserar sedan resultaten från Microsoft Azure-testplaner. Azure Test Plans innehåller alla verktyg som du behöver för att testa dina program. Du kan skapa och köra manuella testplaner, generera automatiserade tester och samla in feedback från intressenter.

  1. I Azure Pipelines spårar du bygget genom vart och ett av stegen.

    Du ser att aktiviteten Kör enhetstester – Versionskörning kör enhetstesterna precis som du gjorde manuellt från kommandoraden.

    A screenshot of Azure Pipelines showing console output from running unit tests.

  2. Gå tillbaka till pipelinesammanfattningen.

  3. Gå till fliken Tester .

    Du ser en sammanfattning av testkörningen. Alla fem testerna har godkänts.

    A screenshot of Azure Pipelines showing the Tests tab with 5 total tests run and 100 percent passing.

  4. I Azure DevOps väljer du Testplaner och sedan Körningar.

    A screenshot of Azure DevOps navigation menu with Test Plans section and Runs tab highlighted.

    Du ser de senaste testkörningarna, inklusive den du precis körde.

  5. Dubbelklicka på den senaste testkörningen.

    Du ser en sammanfattning av resultaten.

    A screenshot of Azure DevOps test run results summary showing 5 passed tests.

    I det här exemplet har alla fem testerna godkänts. Om några tester misslyckades kan du gå till byggaktiviteten för att få mer information.

    Du kan också ladda ned TRX-filen för att undersöka den via Visual Studio eller något annat visualiseringsverktyg.

Även om du bara har lagt till ett test är det en bra början och det åtgärdar det omedelbara problemet. Nu har teamet en plats där de kan lägga till fler tester och köra dem när de förbättrar sin process.

Slå samman grenen till main

Om du är nöjd med resultatet i ett verkligt scenario kan du slå samman grenen unit-tests till main, men för korthet hoppar vi över den processen för tillfället.