Ejercicio: realizar pruebas de cobertura de código
De manera muy similar a la herramienta que usa para las pruebas unitarias, la que utiliza para la cobertura de código depende del lenguaje de programación y del marco de trabajo de la aplicación.
Cuando se tienen como destino aplicaciones de .NET que deben ejecutarse en Linux, coverlet es una opción muy utilizada. Coverlet es una biblioteca de cobertura de código multiplataforma para .NET.
¿Cómo se realiza la cobertura de código en .NET?
La manera de recopilar la cobertura de código depende de qué lenguaje de programación y de qué marcos de trabajo utiliza, así como de qué herramientas de cobertura de código están disponibles.
En nuestro escenario de Tailspin, encontramos que:
Visual Studio en Windows proporciona una manera de realizar la cobertura de código.
Pero, como estamos realizando la compilación en Linux, podemos usar coverlet, una biblioteca de cobertura de código multiplataforma para .NET.
El proyecto de prueba unitaria requiere el paquete coverlet.msbuild de NuGet.
Los resultados de cobertura de código se escriben en un archivo XML para que otra herramienta pueda procesarlos. Azure Pipelines admite los formatos de resultados de cobertura Cobertura y JaCoCo.
Para este módulo, usamos Cobertura.
Para convertir los resultados de cobertura de Cobertura a un formato legible, podemos usar una herramienta denominada ReportGenerator.
ReportGenerator proporciona muchos formatos, incluido HTML. Los formatos HTML generan informes detallados para cada clase del proyecto .NET.
En concreto, hay un formato HTML denominado HtmlInline_AzurePipelines que proporciona una apariencia visual que coincide con Azure Pipelines.
¿Cómo se administran las herramientas de .NET?
Una herramienta de .NET, como ReportGenerator
, es un paquete especial de NuGet que contiene una aplicación de consola. Puede administrar una herramienta de .NET como herramienta global o local.
Una herramienta global se instala en una ubicación centralizada y se le puede llamar desde cualquier directorio. Una versión de una herramienta global se usa para todos los directorios del equipo.
Una herramienta local es una copia más aislada de una herramienta de .NET que tiene por ámbito un directorio específico. El ámbito permite que distintos directorios contengan versiones diferentes de la misma herramienta.
Usará un archivo de manifiesto con el fin de administrar herramientas locales para un directorio determinado. Este archivo estará en formato JSON y se denominará normalmente dotnet-tools.json. Un archivo de manifiesto le permite describir las versiones de herramientas específicas que necesita para compilar o ejecutar la aplicación.
Al incluir el archivo de manifiesto en el control de código fuente y los orígenes de la aplicación, los desarrolladores y los sistemas de compilación podrán ejecutar el comando dotnet tool restore
para instalar todas las herramientas enumeradas en el archivo de manifiesto. Cuando necesite una versión más reciente de una herramienta local, solo tendrá que actualizar la versión en el archivo de manifiesto.
Para mantener los elementos más aislados, trabajará con herramientas locales en este módulo. Creará un manifiesto de herramienta que incluya la herramienta ReportGenerator
. También modificará la canalización de compilación para instalar la herramienta ReportGenerator
y convertir los resultados de la cobertura de código a lenguaje natural.
Ejecutar localmente la cobertura de código
Antes de escribir cualquier código de canalización, puede probar los elementos manualmente para comprobar el proceso.
En Visual Studio Code, abra el terminal integrado.
Ejecute el comando
dotnet new
siguiente para crear un archivo de manifiesto de la herramienta local.dotnet new tool-manifest
El comando creará un archivo denominado .config/dotnet-tools.json.
Ejecute el comando
dotnet tool install
siguiente para instalar ReportGenerator:dotnet tool install dotnet-reportgenerator-globaltool
Este comando instalará la versión más reciente de
ReportGenerator
y agregará una entrada al archivo de manifiesto de la herramienta.Ejecute el comando
dotnet add package
siguiente para agregar el paquetecoverlet.msbuild
al proyecto Tailspin.SpaceGame.Web.Tests:dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
Ejecute el comando
dotnet test
siguiente para realizar las pruebas unitarias y recopilar los resultados de la cobertura de código:Nota:
Si usa el terminal de PowerShell en Visual Studio, el carácter de continuación de línea es un acento grave (`), por lo que debe usar ese carácter en lugar del carácter de barra diagonal inversa (\) para los comandos de varias líneas.
dotnet test --no-build \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=cobertura \ /p:CoverletOutput=./TestResults/Coverage/
Si se produce un error en el comando, intente ejecutarlo de la siguiente manera:
MSYS2_ARG_CONV_EXCL="*" dotnet test --no-build \ --configuration Release \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=cobertura \ /p:CoverletOutput=./TestResults/Coverage/
Este comando es similar al que ejecutó anteriormente. Las marcas
/p:
indican a coverlet qué formato de cobertura de código se va a utilizar y dónde se van a colocar los resultados.Ejecute el comando
dotnet tool run
siguiente para usarReportGenerator
con el fin de convertir el archivo Cobertura a HTML:dotnet tool run reportgenerator \ -- -reports:./Tailspin.SpaceGame.Web.Tests/TestResults/Coverage/coverage.cobertura.xml \ -targetdir:./CodeCoverage \ -reporttypes:HtmlInline_AzurePipelines
En la carpeta CodeCoverage de la raíz del proyecto, aparecerán muchos archivos HTML.
En Visual Studio Code, expanda la carpeta CodeCoverage, haga clic con el botón derecho en index.htm y seleccione Mostrar en el Explorador de archivos (Mostrar en el Finder en macOS o Abrir carpeta de contenido en Linux).
En el Explorador de Windows (Finder en macOS), haga doble clic en index.htm para abrirlo en un explorador web.
Verá el resumen del informe de cobertura.
Desplácese hasta el final de la página para ver un desglose de cobertura por tipo de clase.
Seleccione el vínculo a
TailSpin.SpaceGame.Web.LocalDocumentDBRepository<T>
para ver más detalles.Verá que las pruebas unitarias cubren el método
GetItemsAsync
, mientras que el métodoCountItemsAsync
no tiene ninguna cobertura.Esto tiene sentido, ya que el método de prueba
FetchOnlyRequestedGameRegion
llama al métodoGetItemsAsync
, pero no llama al métodoCountItemsAsync
. (Para revisar el código de prueba, examine el archivo DocumentDBRepository_GetItemsAsyncShould.cs).
Crear una rama
Ahora que puede crear localmente un informe de cobertura de código, ya puede agregar tareas a la canalización de compilación, que realizará las mismas tareas.
En esta sección, creará una rama denominada code-coverage
, basada en la rama unit-tests
para mantener el trabajo. En la práctica, lo habitual sería crear esta rama a partir de la rama main
.
En Visual Studio Code, abra el terminal integrado.
En el terminal, ejecute el comando
git checkout
siguiente para crear una rama denominadacode-coverage
:git checkout -B code-coverage
Incorporación de tareas de compilación
En esta sección, agregará tareas que medirán la cobertura de código en la canalización de compilación.
En Visual Studio Code, modifique azure-pipelines.yml de la manera siguiente:
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()
Esta versión se compila en base a la configuración existente. Este es un resumen de las novedades:
Tarea de Azure Pipelines Nombre para mostrar Descripción DotNetCoreCLI@2
Instalar las herramientas de .NET desde un manifiesto local Instala las herramientas enumeradas en el archivo de manifiesto dotnet-tools.json DotNetCoreCLI@2
Ejecutar pruebas unitarias: $(buildConfiguration) Ejecuta pruebas unitarias y también recopila la cobertura de código en formato Cobertura DotNetCoreCLI@2
Crear el informe de cobertura de código Convierte los resultados de Cobertura a HTML PublishCodeCoverageResults@1
Publicar el informe de cobertura de código Publica el informe en la canalización
Confirmación de los cambios e inserción de estos en la rama de GitHub
Aquí podrá insertar los cambios en GitHub y ver la ejecución de la canalización. Recuerde que actualmente está en la rama code-coverage
.
Aunque no es obligatorio, aquí agregará y confirmará cada archivo por separado para que cada cambio esté asociado a un mensaje de confirmación descriptivo.
En Visual Studio Code, vaya al terminal.
Agregue y confirme el archivo Tailspin.SpaceGame.Web.Tests.csproj, que ahora contiene una referencia al paquete
coverlet.msbuild
:git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git commit -m "Add coverlet.msbuild package"
Agregue y confirme el archivo de manifiesto de la herramienta (dotnet-tools.json):
git add .config/dotnet-tools.json git commit -m "Add code coverage"
Agregue y confirme azure-pipelines.yml, que contiene la configuración de compilación actualizada:
git add azure-pipelines.yml git commit -m "Add code coverage"
Inserte la rama
code-coverage
en GitHub.git push origin code-coverage
Vea cómo Azure Pipelines ejecuta las pruebas
Aquí verá las pruebas que se ejecutan en la canalización y, después, visualizará los resultados de Azure Test Plans.
En Azure Pipelines, realice el seguimiento de la compilación a lo largo de cada uno de los pasos.
Cuando finalice la compilación, vuelva a la página de resumen y seleccione la pestaña Cobertura de código.
Verá los mismos resultados que cuando ejecutó las pruebas localmente.
Como paso opcional, puede explorar los resultados de Azure Pipelines.
Adición de un widget de panel
En la sección anterior, agregó el widget Tendencia de los resultado de las pruebas al panel, que permite a otros usuarios revisar rápidamente las tendencias de los resultados de las pruebas a lo largo del tiempo.
Aquí agregará un segundo widget que resume la cobertura de código.
Desde una nueva pestaña del explorador, vaya a marketplace.visualstudio.com.
En la pestaña Azure DevOps, busque code coverage.
Seleccione Code Coverage Widgets (Widgets de cobertura de código) (publicados por Shane Davis).
Seleccione Obtener gratis.
Seleccione la organización de Azure DevOps en la lista desplegable.
Seleccione Instalar.
Vuelva a Azure DevOps.
Vaya a Overview (Información general)>Dashboards (Paneles).
Seleccione Editar.
Busque Code Coverage y seleccione Code Coverage (Cobertura de código).
Arrastre Cobertura de código al lienzo.
Seleccione el icono de engranaje para configurar el widget.
Mantenga todos los valores de configuración predeterminados, a excepción de los siguientes:
- Ancho: Escriba 2.
- Definición de compilación: Seleccione su canalización
- Medida de la cobertura: seleccione Líneas
Seleccione Guardar.
Seleccione Edición finalizada.
En el widget se muestra el porcentaje de código que cubren las pruebas unitarias.
La cobertura de código ya está configurada en la canalización. Aunque la cobertura de código existente es baja, tiene una línea base que se puede mejorar con el tiempo.
Posteriormente, puede configurar Coverlet para comprobar si las pruebas proporcionan un umbral mínimo de cobertura. El umbral puede ser del 30 %, del 50 % o del 80 % en función de sus requisitos. Se producirá un error en la compilación si las pruebas cubren una cantidad inferior.
Eliminación de los archivos de cobertura de código
Recuerde que, al ejecutar Reportgenerator
anteriormente, aparecieron muchos archivos HTML en la carpeta CodeCoverage en la raíz del proyecto.
Estos archivos HTML no están diseñados para incluirse en el control de código fuente, y ya no los necesita. Aunque el archivo .gitignore del proyecto ya está configurado para ignorar todo lo que se incluya en el directorio CodeCoverage, se recomienda eliminar estos archivos para que no se agreguen al repositorio de Git en módulos futuros.
En Visual Studio Code, vaya a la ventana del terminal y, a continuación, en el directorio raíz del proyecto, ejecute este comando:
rm -rf CodeCoverage/