Ejercicio: realizar pruebas de cobertura de código

Completado

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.

  1. En Visual Studio Code, abra el terminal integrado.

  2. 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.

  3. 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.

  4. Ejecute el comando dotnet add package siguiente para agregar el paquete coverlet.msbuild al proyecto Tailspin.SpaceGame.Web.Tests:

    dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
    
  5. 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.

  6. Ejecute el comando dotnet tool run siguiente para usar ReportGenerator 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.

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

  8. 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.

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

  9. Desplácese hasta el final de la página para ver un desglose de cobertura por tipo de clase.

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

  10. 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étodo CountItemsAsync no tiene ninguna cobertura.

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

    Esto tiene sentido, ya que el método de prueba FetchOnlyRequestedGameRegion llama al método GetItemsAsync, pero no llama al método CountItemsAsync. (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.

  1. En Visual Studio Code, abra el terminal integrado.

  2. En el terminal, ejecute el comando git checkout siguiente para crear una rama denominada code-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.

  1. 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.

  1. En Visual Studio Code, vaya al terminal.

  2. 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"
    
  3. 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"
    
  4. 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"
    
  5. 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.

  1. En Azure Pipelines, realice el seguimiento de la compilación a lo largo de cada uno de los pasos.

  2. 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.

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

    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.

  1. Desde una nueva pestaña del explorador, vaya a marketplace.visualstudio.com.

  2. En la pestaña Azure DevOps, busque code coverage.

  3. Seleccione Code Coverage Widgets (Widgets de cobertura de código) (publicados por Shane Davis).

  4. Seleccione Obtener gratis.

  5. Seleccione la organización de Azure DevOps en la lista desplegable.

  6. Seleccione Instalar.

  7. Vuelva a Azure DevOps.

  8. Vaya a Overview (Información general)>Dashboards (Paneles).

  9. Seleccione Editar.

  10. Busque Code Coverage y seleccione Code Coverage (Cobertura de código).

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

  11. Arrastre Cobertura de código al lienzo.

  12. Seleccione el icono de engranaje para configurar el widget.

  13. 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
  14. Seleccione Guardar.

  15. Seleccione Edición finalizada.

    En el widget se muestra el porcentaje de código que cubren las pruebas unitarias.

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

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/