Ejercicio: corregir una prueba con errores

Completado

En este momento, dispone de una manera de ejecutar las pruebas unitarias a medida que los cambios se mueven a través de la canalización de compilación. También tiene una forma de medir la cantidad de código que cubren las pruebas.

Siempre se recomienda ejecutar todas las pruebas localmente antes de enviarlas a la canalización. Pero ¿qué sucede cuando un usuario se olvida y envía un cambio que interrumpe la compilación?

En esta unidad, corregirá una compilación interrumpida a causa de una prueba unitaria con errores. Aquí podrá:

  • Obtenga el código de inicio de GitHub.
  • Agregue herramientas de cobertura de código al proyecto.
  • Enviará el código al repositorio.
  • Verá cómo la canalización se ejecuta automáticamente y se producen errores en las pruebas unitarias.
  • Reproducirá el error localmente.
  • Analizará y corregirá el error.
  • Enviará una corrección y verá cómo la compilación se realiza correctamente.

Revisar la nueva prueba unitaria

La característica más reciente del equipo implica la tabla de clasificación. Es necesario obtener el número de puntuaciones de la base de datos para que podamos escribir una prueba unitaria para comprobar el método IDocumentDBRepository<T>.GetItemsAsync.

Este es el aspecto de la prueba. Todavía no es necesario agregar ningún código.

[TestCase(0, ExpectedResult=0)]
[TestCase(1, ExpectedResult=1)]
[TestCase(10, ExpectedResult=10)]
public int ReturnRequestedCount(int count)
{
    const int PAGE = 0; // take the first page of results

    // Fetch the scores.
    Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
        score => true, // return all scores
        score => 1, // we don't care about the order
        PAGE,
        count // fetch this number of results
    );
    IEnumerable<Score> scores = scoresTask.Result;

    // Verify that we received the specified number of items.
    return scores.Count();
}

Recuerde que en una prueba NUnit, TestCase proporciona datos insertados que se usan para probar ese método. NUnit llama al método de prueba unitaria ReturnRequestedCount de una forma similar a la siguiente:

ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);

Esta prueba también usa la propiedad ExpectedResult para simplificar el código de prueba y ayudar a que su intención sea más clara. NUnit compara automáticamente el valor devuelto con el valor de esta propiedad y, de esta manera, elimina la necesidad de llamar explícitamente a la aserción.

Elegiremos algunos valores que representan consultas típicas. También incluiremos 0 para cubrir ese caso perimetral.

Captura de la rama de GitHub

Como hizo anteriormente, capture la rama failed-test de GitHub y restaure (o cambie a) esa rama.

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

  2. Ejecute los comandos git fetch y git checkout siguientes para descargar una rama denominada failed-test desde el repositorio de Microsoft y cambie a esa rama:

    git fetch upstream failed-test
    git checkout -B failed-test upstream/failed-test
    

    Con fines de aprendizaje, denominaremos la rama failed-test. En la práctica, denominaría una rama en función de su propósito o característica.

  3. Ejecute estos comandos para crear un archivo de manifiesto de la herramienta local, instale la herramienta ReportGenerator y agregue el paquete coverlet.msbuild al proyecto de pruebas:

    dotnet new tool-manifest
    dotnet tool install dotnet-reportgenerator-globaltool
    dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
    

    Necesita este paso porque la rama failed-test no contiene el trabajo que ha agregado a la rama unit-tests.

  4. Agregue el archivo del proyecto de prueba y el archivo de manifiesto de la herramienta al índice de ensayo y confirme los cambios.

    git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj
    git add .config/dotnet-tools.json
    git commit -m "Configure code coverage tests"
    
  5. Ejecute el comando git push siguiente para cargar la rama failed-test en el repositorio de GitHub:

    git push origin failed-test
    

Ver el error de prueba en la canalización

Supongamos que tenía prisa y envió su trabajo sin ejecutar las pruebas una última vez. Por suerte, la canalización puede ayudarle a detectar problemas anticipadamente cuando hay pruebas unitarias. Puede ver esto aquí.

  1. En Azure Pipelines, realice un seguimiento de la compilación mientras se ejecuta por la canalización.

  2. Expanda la tarea Ejecutar pruebas unitarias - Liberar mientras se ejecuta.

    Verá que el método de prueba ReturnRequestedCount produce un error.

    A screenshot of Azure Pipelines dashboard showing output log of an assertion failure on the unit test, expecting 10 but was 9.

    La prueba se supera cuando el valor de entrada es 0, pero se produce un error cuando el valor de entrada es 1 o 10.

    La compilación se publica en la canalización solo cuando la tarea anterior se realiza correctamente. En este caso, no se publicó la compilación debido a un error en las pruebas unitarias. Esto evita que la compilación se interrumpa accidentalmente para otros usuarios.

En la práctica, no siempre realizará un seguimiento manual de la compilación mientras se ejecuta. Estas son algunas formas de detectar el error:

  • Notificación por correo electrónico de Azure DevOps

    Puede configurar Azure DevOps para que le envíe una notificación por correo electrónico cuando la compilación se haya completado. La línea del asunto empieza con "[Error de compilación]" cuando se produce un error en la compilación.

    A screenshot of a portion of a build failed email notification.

  • Azure Test Plans

    En Azure DevOps, seleccione Test Plans y, después, Runs (Ejecuciones). Verá las series de pruebas recientes, incluida la que se acaba de ejecutar. Seleccione la última prueba completada. Verá que se produjeron errores en dos de las ocho pruebas.

    A screenshot of Azure DevOps test run outcome showing two of eight failed tests as a ring chart.

  • El panel

    En Azure DevOps, seleccione Overview (Información general) y, después, Dashboards (Paneles). Verá que el error se muestra en el widget Tendencia de los resultados de pruebas. El widget Code Coverage (Cobertura de código) está en blanco, lo que indica que no se ha ejecutado la cobertura de código.

    A screenshot of Azure DevOps dashboard trend chart widget showing two failed test in the last test run.

  • La notificación de compilación

    Aunque la rama failed-test no incluye la notificación de compilación en el archivo README.md, esto es lo que vería en GitHub cuando se produjera un error en la compilación:

    A screenshot of Azure Pipelines build badge on GitHub indicating a failure.

Analizar los errores de las pruebas

Cuando se produce un error en las pruebas unitarias, normalmente tiene dos opciones, según la naturaleza del error:

  • Si la prueba revela un defecto en el código, corrija el código y vuelva a ejecutar las pruebas.
  • Si la funcionalidad ha cambiado, ajuste la prueba para que coincida con los nuevos requisitos.

Reproducir el error localmente

En esta sección, reproducirá el error localmente.

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

  2. En el terminal, ejecute este comando dotnet build para compilar la aplicación:

    dotnet build --configuration Release
    
  3. En el terminal, ejecute este comando dotnet test para realizar las pruebas unitarias:

    dotnet test --no-build --configuration Release
    

    Debería ver los mismos errores que en la canalización. A continuación, se muestra parte de la salida:

    Starting test execution, please wait...
    A total of 1 test files matched the specified pattern.
      Failed ReturnRequestedCount(1) [33 ms]
      Error Message:
         Expected: 1
      But was:  0
    
      Stack Trace:
         at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)
    
      Failed ReturnRequestedCount(10) [1 ms]
      Error Message:
         Expected: 10
      But was:  9
    
      Stack Trace:
         at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)
    
    
    Failed!  - Failed:     2, Passed:     6, Skipped:     0, Total:     8, Duration: 98 ms
    

Encontrar la causa del error

Observará que cada prueba con errores genera un resultado que representa una unidad menos. Por ejemplo, cuando se espera 10, la prueba devuelve 9.

Observe el código fuente para el método que se está probando: LocalDocumentDBRepository<T>.GetItemsAsync. Debería aparecer esto:

public Task<IEnumerable<T>> GetItemsAsync(
    Func<T, bool> queryPredicate,
    Func<T, int> orderDescendingPredicate,
    int page = 1, int pageSize = 10
)
{
    var result = _items
        .Where(queryPredicate) // filter
        .OrderByDescending(orderDescendingPredicate) // sort
        .Skip(page * pageSize) // find page
        .Take(pageSize - 1); // take items

    return Task<IEnumerable<T>>.FromResult(result);
}

En este escenario, podría comprobar GitHub para ver si el archivo se cambió recientemente.

A screenshot of GitHub showing a file diff where a minus one operation was added.

Sospecha que pageSize - 1 devuelve un resultado menos y que debería ser, simplemente, pageSize. En nuestro escenario, se trata de un error realizado al enviar trabajo sin pruebas, pero en un escenario real podría comprobar con el desarrollador que cambió el archivo en GitHub para determinar el motivo del cambio.

Sugerencia

El análisis y la colaboración también tienen lugar en GitHub. Puede comentar una solicitud de incorporación de cambios o abrir un problema.

Corregir el error

En esta sección, corregirá el error volviendo a cambiar el código a su estado original y ejecutando las pruebas para comprobar la corrección.

  1. En Visual Studio Code, abra Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs desde el Explorador de archivos.

  2. Modifique el método GetItemsAsync tal y como se muestra aquí:

    public Task<IEnumerable<T>> GetItemsAsync(
        Func<T, bool> queryPredicate,
        Func<T, int> orderDescendingPredicate,
        int page = 1, int pageSize = 10
    )
    {
        var result = _items
            .Where(queryPredicate) // filter
            .OrderByDescending(orderDescendingPredicate) // sort
            .Skip(page * pageSize) // find page
            .Take(pageSize); // take items
    
        return Task<IEnumerable<T>>.FromResult(result);
    }
    

    Esta versión cambia de pageSize - 1 a pageSize.

  3. Guarde el archivo.

  4. En el terminal integrado, compile la aplicación.

    dotnet build --configuration Release
    

    Debería ver que la compilación se realice correctamente.

    En la práctica, podría ejecutar la aplicación y probarla brevemente. Con fines de aprendizaje, omitiremos eso por ahora.

  5. En el terminal, ejecute las pruebas unitarias.

    dotnet test --no-build --configuration Release
    

    Verá que se superan las pruebas.

    Starting test execution, please wait...
    A total of 1 test files matched the specified pattern.
    
    Passed!  - Failed:     0, Passed:     8, Skipped:     0, Total:     8, Duration: 69 ms
    
  6. En el terminal integrado, agregue cada archivo modificado al índice, confirme los cambios e inserte la rama en GitHub.

    git add .
    git commit -m "Return correct number of items"
    git push origin failed-test
    

    Sugerencia

    El punto (.) de este ejemplo de git add es un carácter comodín. Coincide con todos los archivos no almacenados provisionalmente en el directorio actual y todos los subdirectorios.

    Antes de utilizar este carácter comodín, se recomienda ejecutar git status antes de la confirmación para asegurarse de estar realizando el ensayo con los archivos previstos.

  7. Vuelva a Azure Pipelines. Observe cómo el cambio se mueve por la canalización. Se superarán las pruebas y se realizará correctamente la compilación global.

    Si quiere, puede seleccionar las pestañas Tests (Pruebas) y Code Coverage (Cobertura de código) cuando finalice la compilación para comprobar los resultados de las pruebas.

    También puede consultar el panel para ver la tendencia de los resultados actualizada.

    A screenshot of Azure DevOps dashboard trend chart widget showing a return to all tests passing.

Magnífico. Se corrigió la compilación. A continuación, aprenderá a limpiar el entorno de Azure DevOps.