Esercizio - Eseguire i test di code coverage
In modo simile allo strumento usato per il testing unità, lo strumento usato per il code coverage dipende dal linguaggio di programmazione e dal framework applicazione.
Se le applicazioni .NET sono destinate all'esecuzione in Linux, una delle opzioni più diffuse è coverlet. Coverlet è una libreria di code coverage multipiattaforma per .NET.
Come viene eseguito il code coverage in .NET?
Il modo in cui si raccolgono i dati di code coverage dipende dal linguaggio di programmazione e dal framework in uso, oltre che dagli strumenti disponibili.
Nello scenario di Tailspin è stato rilevato che:
Visual Studio in Windows offre un'opzione per eseguire il code coverage.
Poiché si sta creando in Linux, è tuttavia possibile usare coverlet, una libreria di code coverage multipiattaforma per .NET.
Il progetto di unit test richiede il pacchetto NuGet coverlet.msbuild.
I risultati del code coverage vengono scritti in un file XML, in modo che possano essere elaborati da un altro strumento. Azure Pipelines supporta i formati dei risultati Cobertura e JaCoCo.
Per questo modulo si usa Cobertura.
Per convertire i risultati Cobertura in un formato leggibile, è possibile usare uno strumento chiamato ReportGenerator.
ReportGenerator offre molti formati, tra cui HTML. I formati HTML creano report dettagliati per ogni classe in un progetto .NET.
In particolare, il formato HTML denominato HtmlInline_AzurePipelines fornisce una rappresentazione visiva che corrisponde ad Azure Pipelines.
Come è possibile gestire gli strumenti .NET?
Uno strumento .NET, come ad esempio ReportGenerator
, è uno speciale pacchetto NuGet che contiene un'applicazione console. È possibile gestire uno strumento .NET come strumento globale o locale.
Uno strumento globale viene installato in una posizione centralizzata e può essere chiamato da qualsiasi directory. Per tutte le directory nel computer viene usata una versione di uno strumento globale.
Uno strumento locale è una copia più isolata di uno strumento .NET il cui ambito è una directory specifica. L'ambito consente a directory diverse di contenere versioni diverse dello stesso strumento.
Per gestire gli strumenti locali per una determinata directory viene usato un file manifesto. Il file è in formato JSON ed è in genere denominato dotnet-tools.json. Un file manifesto consente di descrivere le versioni specifiche dello strumento necessarie per compilare o eseguire l'applicazione.
Quando si include il file manifesto nel controllo del codice sorgente insieme alle origini dell'applicazione, gli sviluppatori e i sistemi di compilazione possono eseguire il comando dotnet tool restore
per installare tutti gli strumenti elencati nel file manifesto. Quando è necessaria una versione più recente di uno strumento locale, è sufficiente aggiornare la versione nel file manifesto.
Per isolare maggiormente le operazioni, in questo modulo si useranno gli strumenti locali. Si creerà il manifesto di uno strumento, incluso lo strumento ReportGenerator
. Si modificherà inoltre la pipeline di compilazione per installare lo strumento ReportGenerator
in modo da convertire i risultati del code coverage in un formato chiaramente leggibile.
Eseguire il code coverage in locale
Prima di scrivere codice della pipeline, è possibile provare manualmente le operazioni per verificare il processo.
Aprire il terminale integrato in Visual Studio Code.
Eseguire il comando
dotnet new
seguente per creare un file manifesto dello strumento locale.dotnet new tool-manifest
Il comando crea un file denominato .config/dotnet-tools.json.
Eseguire il comando
dotnet tool install
seguente per installare ReportGenerator:dotnet tool install dotnet-reportgenerator-globaltool
Con questo comando viene installata la versione più recente di
ReportGenerator
e viene aggiunta una voce al file manifesto dello strumento.Eseguire il comando
dotnet add package
seguente per aggiungere il pacchettocoverlet.msbuild
al progetto Tailspin.SpaceGame.Web.Tests:dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
Eseguire il comando
dotnet test
seguente per eseguire gli unit test e raccogliere i dati di code coverage:Nota
Se si usa il terminale di PowerShell in Visual Studio, il carattere di continuazione della riga è un backtick (`), quindi usare tale carattere al posto del carattere barra rovesciata (\) per i comandi da più righe.
dotnet test --no-build \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=cobertura \ /p:CoverletOutput=./TestResults/Coverage/
Se il comando non riesce, provare a eseguirlo come illustrato di seguito:
MSYS2_ARG_CONV_EXCL="*" dotnet test --no-build \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=cobertura \ /p:CoverletOutput=./TestResults/Coverage/
Questo comando è simile a quello eseguito in precedenza. I flag
/p:
indicano a Coverlet quale formato di code coverage usare e dove inserire i risultati.Eseguire il comando
dotnet tool run
seguente per usareReportGenerator
in modo da convertire il file di Cobertura in HTML:dotnet tool run reportgenerator \ -- -reports:./Tailspin.SpaceGame.Web.Tests/TestResults/Coverage/coverage.cobertura.xml \ -targetdir:./CodeCoverage \ -reporttypes:HtmlInline_AzurePipelines
Nella cartella CodeCoverage alla radice del progetto sono presenti numerosi file HTML.
In Visual Studio Code espandere la cartella CodeCoverage, fare clic con il pulsante destro del mouse su index.htm, quindi selezionare Visualizza in Esplora risorse (Mostra nel Finder in macOS o Apri cartella contenitore in Linux).
In Esplora risorse (Finder in macOS) fare doppio clic sul file index.htm per aprirlo in un Web browser.
Verrà visualizzato il report riepilogativo di code coverage.
Scorrere alla fine della pagina per visualizzare una suddivisione del code coverage per tipo di classe.
Per visualizzare altri dettagli, selezionare il collegamento a
TailSpin.SpaceGame.Web.LocalDocumentDBRepository<T>
.Si noti che il metodo
GetItemsAsync
è coperto dagli unit test, mentre il metodoCountItemsAsync
non ha copertura.Questo risultato è previsto, perché il metodo di test
FetchOnlyRequestedGameRegion
chiama il metodoGetItemsAsync
, ma non il metodoCountItemsAsync
. Per esaminare il codice di test, vedere il file DocumentDBRepository_GetItemsAsyncShould.cs.
Creare un ramo
Ora che si è in grado di compilare un report di code coverage in locale, è possibile aggiungere attività alla pipeline di compilazione, che esegue le stesse attività.
In questa sezione verrà creato un ramo denominato code-coverage
, basato sul ramo unit-tests
, per contenere il lavoro. In pratica, questo ramo viene solitamente creato dal ramo main
.
Aprire il terminale integrato in Visual Studio Code.
Nel terminale eseguire il comando
git checkout
seguente per creare un ramo denominatocode-coverage
:git checkout -B code-coverage
Aggiungere attività di compilazione
In questa sezione verranno aggiunte alla pipeline di compilazione le attività che misurano il code coverage.
In Visual Studio Code modificare azure-pipelines.yml come indicato di seguito:
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()
Questa versione si basa sulla configurazione esistente. Ecco un riepilogo delle novità:
Attività di Azure Pipelines Nome visualizzato Descrizione DotNetCoreCLI@2
Installa strumenti .NET Core da un manifesto locale Installa gli strumenti elencati nel file manifesto, dotnet-tools.json DotNetCoreCLI@2
Esegui unit test - $(buildConfiguration) Esegue gli unit test e raccoglie anche i dati di code coverage in formato Cobertura DotNetCoreCLI@2
Crea il report di code coverage Converte l'output di Cobertura in HTML PublishCodeCoverageResults@1
Pubblica il report di code coverage Pubblica il report nella pipeline
Eseguire il commit delle modifiche e il push del ramo in GitHub
A questo punto si eseguirà il push delle modifiche in GitHub e si assisterà all'esecuzione della pipeline. Tenere presente che attualmente ci si trova nel ramo code-coverage
.
Sebbene non sia obbligatorio, ora si aggiungerà ogni file separatamente e si eseguirà il commit in modo che ciascuna modifica venga associata a un messaggio di commit descrittivo.
In Visual Studio Code passare al terminale.
Aggiungere il file Tailspin.SpaceGame.Web.Tests.csproj, che ora contiene un riferimento al pacchetto
coverlet.msbuild
, ed eseguire il commit:git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git commit -m "Add coverlet.msbuild package"
Aggiungere il file manifesto dello strumento, dotnet-tools.json, ed eseguire il commit:
git add .config/dotnet-tools.json git commit -m "Add code coverage"
Aggiungere azure-pipelines.yml, che contiene la configurazione della build aggiornata, ed eseguire il commit:
git add azure-pipelines.yml git commit -m "Add code coverage"
Eseguire il push del ramo
code-coverage
in GitHub.git push origin code-coverage
Osservare l'esecuzione dei test in Azure Pipelines
Ora verranno visualizzati test eseguiti nella pipeline e quindi i risultati prodotti da Azure Test Plans.
In Azure Pipelines tenere traccia della compilazione in ognuno dei passaggi.
Al completamento della build, tornare alla pagina di riepilogo e selezionare la scheda Code coverage.
Vengono visualizzati gli stessi risultati generati quando i test sono stati eseguiti in locale.
Come passaggio facoltativo, è possibile esplorare i risultati in Azure Pipelines.
Aggiungere il widget del dashboard
Nella sezione precedente è stato aggiunto al dashboard il widget Tendenza risultati del test, che consente agli altri utenti di esaminare rapidamente le tendenze dei risultati del test nel corso del tempo.
A questo punto verrà aggiunto un secondo widget per riepilogare i dati di code coverage.
In una nuova scheda del browser passare a marketplace.visualstudio.com.
Nella scheda Azure DevOps cercare code coverage.
Selezionare "Code Coverage Widgets" (pubblicato da Shane Davis).
Selezionare Scarica gratuitamente.
Nell'elenco a discesa selezionare l'organizzazione di Azure DevOps.
Selezionare Installa.
Tornare ad Azure DevOps.
Passare a Panoramica>Dashboard.
Seleziona Modifica
Cercare code coverage, quindi selezionare Code coverage.
Trascinare Code coverage nel canvas.
Per configurare il widget, selezionare l'icona dell'ingranaggio.
Mantenere tutte le impostazioni predefinite, ad eccezione di:
- Larghezza: Immettere 2
- Definizione di compilazione: Selezionare la pipeline
- Misurazione della copertura: selezionare Linee
Seleziona Salva.
Selezionare Modifica completata.
Il widget mostra la percentuale di code coverage degli unit test.
A questo punto il code coverage è configurato nella pipeline. Anche se l'attuale percentuale di code coverage è bassa, è disponibile una baseline che è possibile migliorare nel corso del tempo.
In seguito è possibile configurare Coverlet in modo che verifichi se i test forniscono una soglia minima di copertura. La soglia potrebbe essere pari al 30%, al 50% o all'80% di copertura, a seconda dei propri requisiti. La compilazione avrà esito negativo se i test coprono un valore inferiore a questo importo.
Rimuovere i file di code coverage
Ricordare che, quando è stato eseguito Reportgenerator
in precedenza, nella cartella CodeCoverage alla radice del progetto sono comparsi numerosi file HTML.
Questi file HTML non sono destinati a essere inclusi nel controllo del codice sorgente e non sono più necessari. Anche se il file con estensione gitignore del progetto è già configurato in modo da ignorare qualsiasi contenuto della directory CodeCoverage, è opportuno eliminare questi file affinché non vengano aggiunti al repository Git nei moduli futuri.
In Visual Studio Code passare alla finestra del terminale, quindi, nella directory radice del progetto eseguire il comando seguente:
rm -rf CodeCoverage/