Cvičení – přidání testů jednotek do vaší aplikace

Dokončeno

V této lekci přidáme testy jednotek do automatizovaného sestavení, které jsme vytvořili pomocí Microsoft Azure Pipelines. Regresní chyby se plíží do kódu vašeho týmu a porušují funkce filtrování tabulky výsledků. Konkrétně se opakovaně zobrazuje nesprávný herní režim.

Tento problém znázorňuje následující obrázek. Když uživatel vybere "Milky Way", aby zobrazil pouze skóre z této herní mapy, získá výsledky z jiných herních map, jako je Andromeda.

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

Tým chce chybu zachytit, než dosáhne testerů. Testování jednotek je skvělý způsob, jak automaticky testovat výskyt chyb regrese.

Přidání testů jednotek v tomto okamžiku v procesu poskytne týmu počáteční začátek, když vylepšuje webovou aplikaci Space Game . Aplikace používá k ukládání nejvyšších skóre a profilů hráčů databázi dokumentů. V tuto chvíli používá místní testovací data. Později plánují připojit aplikaci k živé databázi.

Mnoho architektur testování jednotek je k dispozici pro aplikace jazyka C#. Použijeme NUnit, protože je oblíbená pro komunitu.

Tady je test jednotek, se kterým pracujete:

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

Tabulku výsledků můžete filtrovat pomocí libovolné kombinace typu hry a herní mapy.

Tento test posílá do tabulky výsledků dotazy na nejlepší výsledky a ověřuje, že každý výsledek odpovídá zadané herní mapě.

U testovací metody nástroje NUnit poskytuje funkce TestCase vložená data, která se používají k otestování této metody. V této části NUnit volá metodu FetchOnlyRequestedGameRegion testu jednotek následujícím způsobem:

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

Všimněte si volání kontrolní metody Assert.That na konci testu. Kontrolní výraz je podmínka nebo příkaz, u kterých deklarujete, že mají hodnotu True. Pokud je výsledkem podmínky hodnota False, může to znamenat chybu ve vašem kódu. NUnit spouští každou testovací metodu pomocí vložených dat, která určíte, a zaznamenává výsledek jako úspěšný nebo neúspěšný test.

Mnoho rozhraní pro testování jednotek poskytuje metody ověřování, které se podobají přirozenému jazyku. Tyto metody usnadňují čtení testů a pomáhají mapovat testy na požadavky aplikace.

Představte si kontrolní výraz provedený v tomto příkladu:

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

Tento řádek byste mohli číst jako:

Zkontroluj, že herní oblast u každého vráceného skóre odpovídá zadané herní oblasti.

Tady je postup, který chcete provést:

  1. Načtěte větev z úložiště GitHub, které obsahuje testy jednotek.
  2. Spusťte testy místně a ověřte, že jsou úspěšné.
  3. Do konfigurace vašeho kanálu přidejte úlohy, které budou spouštět testy a shromažďovat výsledky.
  4. Nasdílejte změny větve do vašeho úložiště v GitHubu.
  5. Sledujte, jak váš projekt v Azure Pipelines automaticky sestavuje aplikaci a spouští testy.

Načtení větve z GitHubu

Tady načtete větev z GitHubu unit-tests a tuto větev si můžete rezervovat nebo přepnout do této větve.

Tato větev obsahuje projekt Space Game , se kterým jste pracovali v předchozích modulech, a konfiguraci Azure Pipelines, se kterou můžete začít.

  1. V editoru Visual Studio Code otevřete integrovaný terminál.

  2. Spuštěním následujících git příkazů načtěte větev pojmenovanou unit-tests z úložiště Microsoftu a pak přepněte na danou větev.

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

    Formát tohoto příkazu umožňuje získat počáteční kód z úložiště Microsoft GitHub, označovaného jako upstream. Za chvíli tuto větev nasdílíte do svého úložiště GitHub, označované jako origin.

  3. Jako volitelný krok otevřete soubor azure-pipelines.yml v editoru Visual Studio Code a seznamte se s počáteční konfigurací. Tato konfigurace připomíná základní konfiguraci, kterou jste vytvořili v modulu Vytvoření kanálu buildu v Azure Pipelines. Sestavuje pouze konfiguraci aplikace pro vydání.

Spouštění testů místně

Před odesláním jakýchkoli testů do kanálu je vhodné všechny testy spouštět místně. Uděláš to tady.

  1. V editoru Visual Studio Code otevřete integrovaný terminál.

  2. Spuštěním příkazu dotnet build sestavte každý projekt v řešení.

    dotnet build --configuration Release
    
  3. Spuštěním následujícího dotnet test příkazu spusťte testy jednotek:

    dotnet test --configuration Release --no-build
    

    Příznak --no-build určuje, že se projekt nemá sestavovat před spuštěním tohoto příkazu. Projekt nemusíte sestavovat, protože jste ho sestavili v předchozím kroku.

    Měli byste vidět, že všech pět testů projde.

    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
    

    V tomto příkladu se testy spustily méně než jednu sekundu.

    Všimněte si, že celkem to bylo pět testů. I když jsme definovali pouze jednu testovací metodu, FetchOnlyRequestedGameRegiontento test běží pětkrát, jednou pro každou herní mapu, jak je uvedeno v TestCase vložených datech.

  4. Spusťte testy podruhé. Tentokrát zadejte možnost --logger, aby se výsledky zapisovaly do souboru protokolu.

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

    Z výstupu vidíte, že se v adresáři TestResults vytvoří soubor TRX.

    Soubor TRX je dokument ve formátu XML, který obsahuje výsledky spuštění testů. Je to oblíbený formát výsledků testů, protože Visual Studio a další nástroje vám můžou pomoct vizualizovat výsledky.

    Později se dozvíte, jak vám azure Pipelines může pomoct vizualizovat a sledovat výsledky testů při jejich procházení kanálem.

    Poznámka:

    Soubory TRX nejsou určené k zahrnutí do správy zdrojového kódu. Soubor .gitignore umožňuje určit, které dočasné a další soubory má Git ignorovat. Soubor .gitignore v našem projektu je už nastavený tak, aby ignoroval všechno v adresáři TestResults.

  5. Jako volitelný krok otevřete v editoru Visual Studio Code soubor DocumentDBRepository_GetItemsAsyncShould.cs ze složky Tailspin.SpaceGame.Web.Tests a prozkoumejte testovací kód. I když vás konkrétně nezajímá sestavování aplikací .NET, může být testovací kód užitečný, protože se podobá kódu, který se může zobrazit v jiných architekturách testování jednotek.

Přidání úloh do konfigurace kanálu

V této části nakonfigurujete kanál buildu tak, aby spouštěl testy jednotek a shromáždí výsledky.

  1. V editoru Visual Studio Code upravte azure-pipelines.yml následujícím způsobem:

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

    Tato verze zavádí úlohu sestavení DotNetCoreCLI@2.

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

    Tato úloha sestavení spouští příkaz dotnet test.

    Všimněte si, že tento úkol neurčuje --logger trx argument, který jste použili při ručním spuštění testů. Argument publishTestResults to přidá za vás. Tento argument dává kanálu pokyn, aby generoval soubor TRX v dočasném adresáři, který bude přístupný prostřednictvím integrované proměnné $(Agent.TempDirectory). Publikuje také výsledky úlohy do kanálu.

    Argument projects určuje všechny projekty jazyka C#, které odpovídají **/*. Tests.csproj." Část ** odpovídá všem adresářům a *. Část Tests.csproj odpovídá všem projektům, jejichž název souboru končí na ". Tests.csproj." Větev unit-tests obsahuje pouze jeden projekt testování jednotek, Tailspin.SpaceGame.Web.Tests.csproj. Zadáním vzoru můžete spouštět více testovacích projektů bez nutnosti upravovat konfiguraci sestavení.

Nasdílení větve do GitHubu

Tady nasdílíte změny do GitHubu a zobrazí se spuštění kanálu. Připomínáme, že se nacházíte ve větvi unit-tests.

  1. V integrovaném terminálu přidejte do indexu azure-pipelines.yml , potvrďte změny a nasdílejte větev do GitHubu.

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

Sledování spouštění testů v Azure Pipelines

Tady uvidíte spuštění testů v kanálu a pak vizualizovat výsledky z testovacích plánů Microsoft Azure. Řešení Azure Test Plans poskytuje všechny nástroje, které potřebujete k úspěšnému testování aplikací. Můžete vytvářet a spouštět ruční testovací plány, generovat automatizované testy a shromažďovat zpětnou vazbu od zúčastněných stran.

  1. V Azure Pipelines trasujte sestavení jednotlivými kroky.

    Uvidíte, že úloha Run unit tests - Release (Spuštění testů jednotek – vydání) spustí testy jednotek stejně, jako jste to udělali manuálně vy z příkazového řádku.

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

  2. Přejděte zpět na souhrn kanálu.

  3. Přesuňte se na kartu Tests (Testy).

    Zobrazí se vám souhrn spuštění testů. Všech pět testů bylo úspěšných.

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

  4. V Azure DevOps vyberte Testovací plány a pak vyberte Spustit.

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

    Zobrazí se vám několik posledních spuštění testů včetně testů, které jste právě spustili.

  5. Poklikejte na poslední testovací běh.

    Zobrazí se vám souhrn výsledků.

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

    V tomto příkladu bylo všech pět testů úspěšných. Pokud nějaké testy selhaly, můžete přejít na úlohu sestavení a získat další podrobnosti.

    Můžete si také stáhnout soubor TRX a prozkoumat ho prostřednictvím sady Visual Studio nebo jiného nástroje pro vizualizaci.

I když jste přidali jenom jeden test, je to dobrý začátek a opraví okamžitý problém. Teď mají členové týmu místo pro přidávání a spouštění dalších testů tak, jak zlepšují svůj proces.

Sloučení větve do hlavní větve

Pokud jste byli s výsledky spokojení, můžete v reálném scénáři sloučit unit-tests větev do main, ale kvůli stručnosti tento proces prozatím přeskočíme.