Übung: Durchführen von Code Coverage Tests

Abgeschlossen

Ebenso wie das Tool für Komponententests hängt das Tool, das Sie für Code Coverage-Tests verwenden, von der Programmiersprache und dem Anwendungsframework ab.

Wenn .NET-Anwendungen unter Linux ausgeführt werden sollen, ist coverlet eine beliebte Wahl. Coverlet ist eine plattformübergreifende Code Coverage-Bibliothek für .NET.

Wie erfolgen Code Coverage-Tests in .NET?

Die Art und Weise Ihrer Code Coverage hängt von der verwendeten Programmiersprache, den verwendeten Frameworks sowie den verfügbaren Code Coverage-Tools ab.

In unserem Tailspin-Szenario finden wir Folgendes:

  • Visual Studio unter Windows bietet eine Möglichkeit, Code Coverage-Tests auszuführen.

  • Da wir Builds jedoch unter Linux erstellen, kann coverlet verwendet werden, eine plattformübergreifende Code Coverage-Bibliothek für .NET.

    Für das Komponententestprojekt ist das NuGet-Paket coverlet.msbuild erforderlich.

  • Code Coverage-Ergebnisse werden in eine XML-Datei geschrieben, damit sie von einem anderen Tool verarbeitet werden können. Azure Pipelines unterstützt die Formate Cobertura und JaCoCo für Abdeckungsergebnisse.

    Für dieses Modul verwenden wir Cobertura.

  • Um Cobertura-Abdeckungsergebnisse in ein lesbares Format zu konvertieren, können wir ein Tool namens ReportGenerator verwenden.

  • ReportGenerator unterstützt eine Reihe von Formaten, einschließlich HTML. Mit den HTML-Formaten können ausführliche Berichte für die einzelnen Klassen in einem .NET-Projekt erstellt werden.

    Insbesondere gibt es ein HTML-Format namens HtmlInline_AzurePipelines, das eine visuelle Darstellung ermöglicht, die Azure Pipelines entspricht.

Wie kann ich .NET-Tools verwalten?

Ein .NET-Tool, z. B. ReportGenerator, ist ein spezielles NuGet-Paket, das eine Konsolenanwendung enthält. Sie können ein .NET-Tool als globales oder lokales Tool verwalten.

Ein globales Tool wird an einem zentralen Speicherort installiert und kann von jedem beliebigen Verzeichnis aus aufgerufen werden. Für alle Verzeichnisse des Computers wird eine Version eines globalen Tools verwendet.

Ein lokales Tool ist ein isoliertes Exemplar eines .NET-Tools, das für ein bestimmtes Verzeichnis gilt. Dadurch können unterschiedliche Verzeichnisse verschiedene Versionen desselben Tools enthalten.

Für die Verwaltung von lokalen Tools für ein bestimmtes Verzeichnis wird eine Manifestdatei verwendet. Diese Datei weist das JSON-Format auf und heißt in der Regel dotnet-tools.json. Mit einer Manifestdatei können Sie die jeweiligen Toolversionen beschreiben, die Sie zum Erstellen oder Ausführen der Anwendung benötigen.

Wenn Sie die Manifestdatei zusammen mit dem Anwendungsquellcode in die Quellcodeverwaltung einfügen, können Entwickler und Buildsysteme den Befehl dotnet tool restore ausführen, um alle in der Manifestdatei aufgeführten Tools zu installieren. Wenn Sie eine neuere Version eines lokalen Tools benötigen, aktualisieren Sie einfach die Version in der Manifestdatei.

In diesem Modul arbeiten Sie aus Gründen der Isolation mit lokalen Tools. Sie erstellen ein Toolmanifest, das das Tool ReportGenerator enthält. Außerdem ändern Sie die Buildpipeline, um das Tool ReportGenerator zu installieren, das Code Coverage-Ergebnisse in ein lesbares Format konvertiert.

Lokale Ausführung von Code Coverage

Bevor Sie einen Pipelinecode schreiben, können Sie versuchen, die einzelnen Schritte manuell durchführen, um den Prozess zu überprüfen.

  1. Öffnen Sie in Visual Studio Code das integrierte Terminal.

  2. Führen Sie den folgenden dotnet new-Befehl aus, um eine lokale Toolmanifestdatei zu erstellen.

    dotnet new tool-manifest
    

    Der Befehl erstellt eine Datei namens .config/dotnet-tools.json.

  3. Führen Sie den folgenden dotnet tool install-Befehl aus, um ReportGenerator zu installieren:

    dotnet tool install dotnet-reportgenerator-globaltool
    

    Dieser Befehl installiert die neueste Version von ReportGenerator und fügt einen Eintrag zur Toolmanifestdatei hinzu.

  4. Führen Sie den folgenden dotnet add package-Befehl aus, um das Paket coverlet.msbuild zum Projekt Tailspin.SpaceGame.Web.Tests hinzuzufügen:

    dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
    
  5. Führen Sie den folgenden dotnet test-Befehl aus, um die Komponententests auszuführen und die Code Coverage zu erfassen:

    Hinweis

    Wenn Sie das PowerShell-Terminal in Visual Studio verwenden, ist das Zeilenfortsetzungszeichen ein Backtick (`), daher verwenden Sie dieses Zeichen anstelle des umgekehrten Schrägstrichs (\) für mehrzeilige Befehle.

    dotnet test --no-build \
      --configuration Release \
      /p:CollectCoverage=true \
      /p:CoverletOutputFormat=cobertura \
      /p:CoverletOutput=./TestResults/Coverage/
    

    Führen Sie den Befehl wie folgt aus, wenn er fehlschlägt:

    MSYS2_ARG_CONV_EXCL="*" dotnet test --no-build \
      --configuration Release \
      /p:CollectCoverage=true \
      /p:CoverletOutputFormat=cobertura \
      /p:CoverletOutput=./TestResults/Coverage/
    

    Dieser Befehl ähnelt dem Befehl, den Sie zuvor ausgeführt haben. Die /p:-Flags teilen Coverlet mit, welches Code Coverage Format verwendet werden soll und wo die Ergebnisse gespeichert werden sollen.

  6. Führen Sie den folgenden dotnet tool run-Befehl aus, um die Cobertura-Datei ReportGenerator in das HTML-Format zu konvertieren:

    dotnet tool run reportgenerator \
      -- -reports:./Tailspin.SpaceGame.Web.Tests/TestResults/Coverage/coverage.cobertura.xml \
      -targetdir:./CodeCoverage \
      -reporttypes:HtmlInline_AzurePipelines
    

    Im Ordner CodeCoverage im Stammverzeichnis des Projekts werden viele HTML-Dateien angezeigt.

  7. Erweitern Sie in Visual Studio Code den Ordner CodeCoverage, klicken Sie mit der rechten Maustaste auf index.htm, und wählen Sie dann Im File Explorer anzeigen (In Finder anzeigen unter macOS oder Enthaltenden Ordner öffnen unter Linux) aus.

  8. Doppelklicken Sie in Windows-Explorer (Finder unter macOS) auf index.htm, um die Datei in einem Webbrowser zu öffnen.

    Die Zusammenfassung des Coverage-Berichts wird angezeigt.

    A screenshot of the local code coverage report summary showing 7.7 percent line coverage.

  9. Scrollen Sie zum unteren Rand der Seite, um eine Abdeckungsaufschlüsselung nach Klassentyp anzuzeigen.

    A screenshot of local coverage report class summary showing coverage stats across classes found in the Tailspin.SpaceGame.Web code.

  10. Wählen Sie den Link zu TailSpin.SpaceGame.Web.LocalDocumentDBRepository<T> aus, um weitere Details anzuzeigen.

    Beachten Sie, dass die GetItemsAsync-Methode von Komponententests abgedeckt wird, die CountItemsAsync-Methode jedoch nicht abgedeckt wird.

    A screenshot of local class coverage detail with a visual representation of unit test coverage for two C# methods, one with all code lines green (covered) and one with all lines red (not covered).

    Dies ergibt einen Sinn, weil die FetchOnlyRequestedGameRegion-Testmethode die GetItemsAsync-Methode, aber nicht die CountItemsAsync-Methode aufruft. (Informationen zum Überprüfen des Testcodes finden Sie in der Datei DocumentDBRepository_GetItemsAsyncShould.cs.)

Erstellen einer Verzweigung

Nachdem Sie nun einen Code Coverage-Bericht lokal erstellen können, können Sie die entsprechenden Aufgaben zu Ihrer Buildpipeline hinzufügen.

In diesem Abschnitt erstellen Sie einen Branch namens code-coverage, der auf dem unit-tests-Branch basiert, der Ihre Arbeit aufnehmen soll. In der Praxis wird dieser Branch üblicherweise im main-Branch erstellt.

  1. Öffnen Sie in Visual Studio Code das integrierte Terminal.

  2. Führen Sie im Terminal den folgenden git checkout-Befehl aus, um einen Branch namens code-coverage zu erstellen:

    git checkout -B code-coverage
    

Hinzufügen von Buildaufgaben

In diesem Abschnitt fügen Sie Aufgaben zu Ihrer Buildpipeline hinzu, um die Code Coverage zu messen.

  1. Ändern Sie in Visual Studio Code azure-pipelines.yml wie folgt:

    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: 'Install .NET tools from local manifest'
      inputs:
        command: custom
        custom: tool
        arguments: 'restore'
    
    - task: DotNetCoreCLI@2
      displayName: 'Run unit tests - $(buildConfiguration)'
      inputs:
        command: 'test'
        arguments: '--no-build --configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
        publishTestResults: true
        projects: '**/*.Tests.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Create code coverage report'
      inputs:
        command: custom
        custom: tool
        arguments: 'run reportgenerator -reports:$(Build.SourcesDirectory)/**/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines'
    
    - task: PublishCodeCoverageResults@1
      displayName: 'Publish code coverage report'
      inputs:
        codeCoverageTool: 'cobertura'
        summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'
    
    - 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()
    

    Diese Version baut auf Ihrer vorhandenen Konfiguration auf. Hier sehen Sie eine Zusammenfassung der neuen Aufgaben:

    Azure Pipelines-Aufgabe `Display name` BESCHREIBUNG
    DotNetCoreCLI@2 Installieren von .Net-Tools aus dem lokalen Manifest Installiert die in der Manifestdatei dotnet-tools.js aufgeführten Tools.
    DotNetCoreCLI@2 Run unit tests - $(buildConfiguration) Führt die Komponententests aus und erfasst die Code Coverage im Cobertura-Format.
    DotNetCoreCLI@2 Create code coverage report Konvertiert die Cobertura-Ausgabe in HTML.
    PublishCodeCoverageResults@1 Publish code coverage report Veröffentlicht den Bericht in der Pipeline.

Committen der Änderungen und Pushen des Branchs an GitHub

In diesem Abschnitt pushen Sie Ihre Änderungen an GitHub. Außerdem wird die Pipeline ausgeführt. Denken Sie daran, dass Sie sich derzeit im code-coverage-Branch befinden.

Obwohl es nicht erforderlich ist, fügen Sie hier die einzelnen Dateien getrennt hinzu und committen diese, um jeder Änderung eine beschreibende Commit-Nachricht zuzuordnen.

  1. Rufen Sie in Visual Studio Code das Terminal auf.

  2. Fügen Sie die Datei Tailspin.SpaceGame.Web.Tests.csproj, die nun einen Verweis auf das coverlet.msbuild-Paket enthält, hinzu und committen Sie die Datei:

    git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj
    git commit -m "Add coverlet.msbuild package"
    
  3. Fügen Sie die Toolmanifestdatei dotnet-tools.js hinzu und committen Sie die Datei:

    git add .config/dotnet-tools.json
    git commit -m "Add code coverage"
    
  4. Fügen Sie die Datei azure-pipelines.yml mit der aktualisierten Buildkonfiguration hinzu und committen Sie die Datei:

    git add azure-pipelines.yml
    git commit -m "Add code coverage"
    
  5. Pushen Sie den Branch code-coverage an GitHub.

    git push origin code-coverage
    

Beobachten der Testausführung in Azure Pipelines

Hier wird gezeigt, wie die Tests in der Pipeline ausgeführt und die Ergebnisse dann in Azure Test Plans visualisiert werden.

  1. Verfolgen Sie die einzelnen Schritte des Buildvorgangs in Azure Pipelines.

  2. Kehren Sie zurück zur Zusammenfassungsseite, nachdem der Build erstellt wurde, und wählen Sie die Registerkarte Code Coverage aus.

    Es werden die gleichen Ergebnisse angezeigt wie bei der lokalen Testausführung.

    A screenshot of Azure Pipelines showing the Code Coverage tab, with code coverage report summary showing 7.7 percent line coverage.

    Optional können Sie die Ergebnisse in Azure Pipelines untersuchen.

Hinzufügen des Dashboardwidgets

Im vorherigen Abschnitt haben Sie das Widget Test Results Trend zu Ihrem Dashboard hinzugefügt, mit dem andere Benutzer Testergebnistrends schnell überblicken können.

Hier fügen Sie ein zweites Widget hinzu, das die Code Coverage zusammenfasst.

  1. Navigieren Sie im Browser auf einer neuen Registerkarte zu marketplace.visualstudio.com.

  2. Suchen Sie auf der Registerkarte Azure DevOps nach Code Coverage.

  3. Wählen Sie Code Coverage Widgets (veröffentlicht von Shane Davis) aus.

  4. Wählen Sie Kostenlos erhalten aus.

  5. Wählen Sie Ihre Azure DevOps-Organisation in der Dropdownliste aus.

  6. Wählen Sie Installieren aus.

  7. Wechseln Sie zurück zu Azure DevOps.

  8. Navigieren Sie zu Overview>Dashboards.

  9. Wählen Sie Bearbeiten aus.

  10. Suchen Sie nach Code Coverage, und wählen Sie dann Code Coverage aus.

    A screenshot of Visual Studio Marketplace showing the Code Coverage widget card.

  11. Ziehen Sie Code Coverage in den Canvas.

  12. Wählen Sie das Zahnradsymbol aus, um das Widget zu konfigurieren.

  13. Übernehmen Sie alle Standardeinstellungen mit Ausnahme von:

    • Breite: Geben Sie 2 ein.
    • Builddefinition: Wählen Sie Ihre Pipeline aus
    • Coverage measurement: Wählen Sie Lines aus
  14. Wählen Sie Speichern aus.

  15. Wählen Sie Bearbeitung abgeschlossen aus.

    Das Widget zeigt den Prozentsatz des Codes an, der von den Komponententests abgedeckt wird.

    A screenshot of Azure DevOps Code Coverage widget showing 8 percent coverage of the sample project.

Sie haben Code Coverage jetzt in ihrer Pipeline eingerichtet. Obwohl die bestehende Code Coverage gering ist, haben Sie eine Baseline, die Sie im Laufe der Zeit verbessern können.

Später können Sie coverlet so konfigurieren, dass geprüft wird, ob Ihre Tests einen minimalen Schwellenwert für die Abdeckung ergeben. Der Schwellenwert kann abhängig von den jeweiligen Anforderungen eine Abdeckung von 30 Prozent, 50 Prozent oder 80 Prozent sein. Der Build schlägt fehl, wenn Ihre Tests weniger als diesen Wert abdecken.

Entfernen von Code Coverage-Dateien

Bei der früheren Ausführung von Reportgenerator wurden im Ordner CodeCoverage im Stammverzeichnis des Projekts zahlreiche HTML-Dateien angezeigt.

Diese HTML-Dateien sollen nicht in die Quellcodeverwaltung einbezogen werden, weil Sie sie nicht mehr benötigen. Obwohl die .gitignore-Datei des Projekts bereits so eingerichtet ist, dass Elemente im CodeCoverage-Verzeichnis ignoriert werden, sollten Sie diese Dateien löschen, damit Sie in zukünftigen Modulen nicht zu Ihrem Git-Repository hinzugefügt werden.

Wechseln Sie in Visual Studio Code zum Terminalfenster, und führen Sie dann im Stammverzeichnis des Projekts den folgenden Befehl aus:

rm -rf CodeCoverage/