Ejercicio: Prueba unitaria de una función de Azure

Completado

La prueba unitaria es una parte fundamental de una metodología Agile. Visual Studio proporciona la plantilla Proyecto de prueba. Use esta plantilla para crear las pruebas unitarias para las aplicaciones; puede aplicar la misma técnica a las pruebas de Azure Functions.

En el escenario de sitio web en línea de relojes de lujo, el equipo de desarrollo tiene una directiva para lograr al menos el 80 % de cobertura de código en las pruebas unitarias. Quiere implementar la misma directiva para Azure Functions.

Aquí verá cómo usar el marco de pruebas xUnit con Visual Studio para probar Azure Functions.

Creación de un proyecto de prueba unitaria

El primer paso consiste en crear un proyecto que contenga las pruebas unitarias y agregarlo a la solución que contiene la aplicación de funciones de Azure. Siga estos pasos para crear un proyecto de prueba unitaria para probar la función WatchInfo.

  1. En la ventana Explorador de soluciones de Visual Studio, haga clic con el botón derecho en la solución WatchPortalFunction y seleccione Agregar y, luego, Nuevo proyecto.

    Captura de pantalla del Explorador de soluciones que muestra el comando Agregar un nuevo proyecto a la solución seleccionada.

  2. En la ventana Agregar un nuevo proyecto, desplácese hacia abajo, seleccione la plantilla de icono Proyecto de prueba de xUnitC#+ y después Siguiente.

    Captura de pantalla de la ventana Agregar nuevo proyecto. La plantilla Proyecto de prueba de xUnit está seleccionada.

  3. Se abre la ventana Configurar el nuevo proyecto. En el campo Nombre de proyecto, escriba WatchFunctionsTests. Aparte del campo Ubicación, seleccione el icono para examinar y, después, seleccione la carpeta WatchPortalFunction.

  4. Seleccione Siguiente. Aparece la ventana Información adicional.

  5. En Versión de .NET Framework de destino. acepte el valor predeterminado de .NET 6.0 (compatibilidad a largo plazo).

  6. Seleccione Crear.

  7. Cuando se agregue el proyecto, haga clic con el botón derecho en el proyecto WatchFunctionTests en la ventana Explorador de soluciones y, a continuación, seleccione Administrar paquetes NuGet.

  8. En la ventana NuGet: WatchFunctionTests, seleccione la pestaña Examinar. En el cuadro Buscar, escriba Microsoft.AspNetCore.Mvc. Seleccione el paquete Microsoft.AspNetCore.Mvc y, luego, Instalar.

    Captura de pantalla de la ventana Administrador de paquetes NuGet. El usuario instala el paquete Microsoft.AspNetCore.Mvc.

    Nota:

    El proyecto de prueba creará un entorno simulado de HTTP. Las clases necesarias para hacer esto se encuentran en el paquete Microsoft.AspNetCore.Mvc.

  9. Espere mientras se instala el paquete. Si aparece el cuadro de mensaje Vista previa de los cambios, seleccione Aceptar. En el cuadro de mensaje Aceptación de la licencia, seleccione Acepto.

  10. Cuando el paquete se haya agregado, vaya a la ventana del Explorador de soluciones, en el proyecto WatchFunctionsTests, haga clic con el botón derecho en el archivo UnitTest1.cs y, a continuación, seleccione Cambiar nombre. Cambie el nombre del archivo a WatchFunctionUnitTests.cs. En el cuadro de mensaje que aparece, seleccione para cambiar el nombre de todas las referencias de UnitTest1 a WatchFunctionUnitTests.

  11. En el proyecto WatchFunctionsTests de la ventana Explorador de soluciones, haga clic con el botón derecho en Dependencias y seleccione Agregar referencia de proyecto.

  12. En la ventana Administrador de referencias, elija el proyecto WatchPortalFunction y seleccione Aceptar.

Incorporación de pruebas unitarias a la función WatchInfo

Ahora puede agregar pruebas unitarias al proyecto de prueba. En el escenario de relojes de lujo, quiere asegurarse de que la función WatchInfo devuelve siempre una respuesta Correcto cuando se proporciona un modelo en la cadena de consulta de una solicitud y una respuesta Incorrecto si la cadena de consulta está vacía o no contiene el parámetro model.

Para comprobar este comportamiento, agregue un par de pruebas Fact a WatchFunctionsTests.

  1. En la ventana Explorador de soluciones, haga doble clic en el archivo WatchFunctionUnitTests.cs para mostrar WatchPortalFunction en la ventana de código.

  2. Agregue las siguientes directivas using a la lista en la parte superior del archivo.

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Http.Internal;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Microsoft.Extensions.Logging.Abstractions;
    
  3. Cambie el nombre del método Test1 a TestWatchFunctionSuccess.

  4. En el cuerpo del método TestWatchFunctionSuccess, agregue el código siguiente. Esta instrucción crea un contexto HTTP y una solicitud HTTP ficticios. La solicitud incluye una cadena de consulta que contiene el parámetro model, que se establece en abc.

    var queryStringValue = "abc";
    var request = new DefaultHttpRequest(new DefaultHttpContext())
    {
        Query = new QueryCollection
        (
            new System.Collections.Generic.Dictionary<string, StringValues>()
            {
                { "model", queryStringValue }
            }
        )
    };
    
  5. Agregue la siguiente instrucción al método. Esta instrucción crea un registrador ficticio.

    var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
  6. Agregue el siguiente código al método. Estas instrucciones invocan la función WatchInfo, que pasa la solicitud y el registrador ficticios como parámetros.

    var response = WatchPortalFunction.WatchInfo.Run(request, logger);
    response.Wait();
    
  7. Agregue el siguiente código al método. Este código comprueba que la respuesta de la función es correcta. En este caso, la función debe devolver la respuesta Correcto, que contiene los datos que se esperan en el cuerpo.

    // Check that the response is an "OK" response
    Assert.IsAssignableFrom<OkObjectResult>(response.Result);
    
    // Check that the contents of the response are the expected contents
    var result = (OkObjectResult)response.Result;
    dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 };
    string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}";
    Assert.Equal(watchInfo, result.Value);
    

    El método completado debe tener el aspecto siguiente.

    [Fact]
    public void TestWatchFunctionSuccess()
    {
        var queryStringValue = "abc";
        var request = new DefaultHttpRequest(new DefaultHttpContext())
        {
            Query = new QueryCollection
            (
                new System.Collections.Generic.Dictionary<string, StringValues>()
                {
                    { "model", queryStringValue }
                }
            )
        };
    
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "OK" response
        Assert.IsAssignableFrom<OkObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (OkObjectResult)response.Result;
        dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 };
        string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}";
        Assert.Equal(watchInfo, result.Value);
    }
    
  8. Agregue otros dos métodos denominados TestWatchFunctionFailureNoQueryString y TestWatchFunctionFailureNoModel. TestWatchFunctionFailureNoQueryString comprueba que la función WatchInfo genera errores leves si no se le proporciona una cadena de consulta. TestWatchFunctionFailureNoModel comprueba el mismo error si la función pasa una cadena de consulta que no contiene un parámetro de modelo.

    [Fact]
    public void TestWatchFunctionFailureNoQueryString()
    {
        var request = new DefaultHttpRequest(new DefaultHttpContext());
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "Bad" response
        Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (BadRequestObjectResult)response.Result;
        Assert.Equal("Please provide a watch model in the query string", result.Value);
    }
    
    [Fact]
    public void TestWatchFunctionFailureNoModel()
    {
        var queryStringValue = "abc";
        var request = new DefaultHttpRequest(new DefaultHttpContext())
        {
            Query = new QueryCollection
            (
                new System.Collections.Generic.Dictionary<string, StringValues>()
                {
                    { "not-model", queryStringValue }
                }
            )
        };
    
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "Bad" response
        Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (BadRequestObjectResult)response.Result;
        Assert.Equal("Please provide a watch model in the query string", result.Value);
    }
    

Ejecución de las pruebas

  1. En la barra de menús superior, en Prueba, seleccione Ejecutar todas las pruebas.

    Captura de pantalla del menú Prueba en Visual Studio. El usuario ha seleccionado Ejecutar -> Todas las pruebas.

  2. En la ventana Explorador de pruebas, las tres pruebas deberían completarse correctamente.

    Captura de pantalla de la ventana de Team Explorer. Las tres pruebas se han ejecutado correctamente.

  3. En el proyecto WatchPortalFunction, en la ventana Explorador de soluciones, haga doble clic en WatchInfo.cs para mostrar el archivo en el editor de código.

  4. Busque el código siguiente.

    // Retrieve the model id from the query string
    string model = req.Query["model"];
    
  5. Cambie la instrucción que establece la variable model de la manera siguiente. Este cambio simula que el desarrollador comete un error en el código.

    string model = req.Query["modelll"];
    
  6. En la barra de menús superior, en Prueba, seleccione Ejecutar todas las pruebas. Esta vez, la prueba TestWatchFunctionSuccess debería generar un error. Este error se debe a que la función WatchInfo no encuentra el parámetro denominado modelll en la cadena de consulta, motivo por el que devuelve una respuesta Incorrecto.

    Captura de pantalla de la ventana de Team Explorer. Error en la prueba TestWatchFunctionSuccess.

En esta lección, hemos visto cómo crear un proyecto de prueba unitaria e implementar pruebas unitarias para una instancia de Azure Functions.