Unidad de prueba Umami.Net -Testing Umami Data Without Using Moq (Español (Spanish))

Unidad de prueba Umami.Net -Testing Umami Data Without Using Moq

Wednesday, 04 September 2024

//

14 minute read

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

En la parte anterior de esta serie donde he probado El Comité recomienda al Estado Parte que incluya en su próximo informe periódico datos estadísticos desglosados por sexo, edad y origen étnico.

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

En la parte anterior he utilizado Moq para darme un Mock<HttpMessageHandler> y devolver el handler utilizado en UmamiClient, este es un patrón común cuando se proba el código que utiliza HttpClient. En este post le mostraré cómo probar el nuevo UmamiDataService Sin usar Moq.

    public static HttpMessageHandler Create()
    {
        var mockHandler = new Mock<HttpMessageHandler>();

        mockHandler.Protected()
            .Setup<Task<HttpResponseMessage>>(
                "SendAsync",
                ItExpr.Is<HttpRequestMessage>(x => x.RequestUri.ToString().Contains("api/send")),
                ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync((HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                // Read the request content
                var requestBody = request.Content != null
                    ? request.Content.ReadAsStringAsync(cancellationToken).Result
                    : null;

                // Create a response that echoes the request body
                var responseContent = requestBody != null
                    ? requestBody
                    : "No request body";


                // Return the response
                return new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StringContent(responseContent, Encoding.UTF8, "application/json")
                };
            });

        return mockHandler.Object;
    }

Por qué usar Moq?

Moq es una potente biblioteca de mocking que le permite crear objetos de mock para interfaces y clases. Se usa ampliamente en la prueba de unidades para separar el código que se está probando de sus dependencias . Sin embargo, hay algunos casos en los que usar Moq puede ser pesado o incluso imposibleMSC3 Por ejemploM SK4 cuando se está testando código que utiliza métodos estáticos o cuando el código bajo prueba está estrechamente coupledo a sus dependencia.

El ejemplo que he dado anteriormente da mucha flexibilidad en la prueba del UmamiClient class, pero también tiene algunas deficiencias. Es el código UGLY de ' y hace muchas cosas que no necesito realmente. UmamiDataService Por lo que respecta a la cuestión de los derechos humanos y las libertades fundamentales, mi delegación apoya plenamente el proyecto de resolución A/C.3/57/L.38, en su forma oralmente revisada.

La Comisión Consultiva en Asuntos Administrativos y de Presupuesto examinó el proyecto de presupuesto por programas para el bienio 2006-2007 (A/60/6 (Sect.

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiDataService es una futura adición a la biblioteca Umami.Net que le permitirá extraer datos de Umami para cosas como ver cuántas visitas tenía una páginaM SK1 qué sucesos se produjeron de un determinado tipo , filtrado por una tonelada de parámetros liek país, ciudadMST4 OSM ST5 tamaño de pantallaMst6 etcM st7 Esto es muy potente pero en estos momentos el Umami API sólo funciona a través de JavaScript. Así que deseando jugar con esos datos, he llevado a cabo el esfuerzo de crear un cliente para él.

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiDataService class se divide en clases parciales múltiples (los métodos son SUPER largosM SK1 por ejemplo aquí' es el PageViews El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la adopción de medidas legislativas, administrativas, judiciales y de otra índole.

Usted puede ver que MUCH del código está construyendo la QueryString desde el que se ha pasado en la clase PageViewsRequest (hay otras formas de hacerlo pero estaM SK1 por ejemplo usando Attributes o trabajos de reflexión aquí).

GetPageViews
    public async Task<UmamiResult<PageViewsResponseModel>> GetPageViews(PageViewsRequest pageViewsRequest)
    {
        if (await authService.LoginAsync() == false)
            return new UmamiResult<PageViewsResponseModel>(HttpStatusCode.Unauthorized, "Failed to login", null);
        // Start building the query string
        var queryParams = new List<string>
        {
            $"startAt={pageViewsRequest.StartAt}",
            $"endAt={pageViewsRequest.EndAt}",
            $"unit={pageViewsRequest.Unit.ToLowerString()}"
        };

        // Add optional parameters if they are not null
        if (!string.IsNullOrEmpty(pageViewsRequest.Timezone)) queryParams.Add($"timezone={pageViewsRequest.Timezone}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Url)) queryParams.Add($"url={pageViewsRequest.Url}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Referrer)) queryParams.Add($"referrer={pageViewsRequest.Referrer}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Title)) queryParams.Add($"title={pageViewsRequest.Title}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Host)) queryParams.Add($"host={pageViewsRequest.Host}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Os)) queryParams.Add($"os={pageViewsRequest.Os}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Browser)) queryParams.Add($"browser={pageViewsRequest.Browser}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Device)) queryParams.Add($"device={pageViewsRequest.Device}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Country)) queryParams.Add($"country={pageViewsRequest.Country}");
        if (!string.IsNullOrEmpty(pageViewsRequest.Region)) queryParams.Add($"region={pageViewsRequest.Region}");
        if (!string.IsNullOrEmpty(pageViewsRequest.City)) queryParams.Add($"city={pageViewsRequest.City}");

        // Combine the query parameters into a query string
        var queryString = string.Join("&", queryParams);

        // Make the HTTP request
        var response = await authService.HttpClient.GetAsync($"/api/websites/{WebsiteId}/pageviews?{queryString}");

        if (response.IsSuccessStatusCode)
        {
            logger.LogInformation("Successfully got page views");
            var content = await response.Content.ReadFromJsonAsync<PageViewsResponseModel>();
            return new UmamiResult<PageViewsResponseModel>(response.StatusCode, response.ReasonPhrase ?? "Success",
                content ?? new PageViewsResponseModel());
        }

        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            await authService.LoginAsync();
            return await GetPageViews(pageViewsRequest);
        }

        logger.LogError("Failed to get page views");
        return new UmamiResult<PageViewsResponseModel>(response.StatusCode,
            response.ReasonPhrase ?? "Failed to get page views", null);
    }
Como usted puede ver esto realmente sólo construye una cadena de consulta. autentica el llamamiento (ver la [El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.](/blog/unittestinglogginginaspnetcore) para algunos detalles sobre esto) y luego hace el llamamiento a la API de Umami. Así que ¿cómo testamos esto ?

La Comisión Consultiva en Asuntos Administrativos y de Presupuesto examinó el proyecto de presupuesto por programas para el bienio 2006-2007 (A/60/6 (Sect.

En contraste con la prueba de UmamiClient, he decidido probar el UmamiDataService sin usar Moq. En lugar de, he creado un simple DelegatingHandler class que me permite interrogar la solicitud y devolver una respuesta. Este es un enfoque mucho más sencillo que usar Moq y me permite probar el UmamiDataService El Comité recomienda al Estado Parte que incluya en su próximo informe periódico información detallada sobre las medidas adoptadas por el Estado parte para eliminar la discriminación contra la mujer. HttpClient.

En el código de abajo usted puede ver simplemente ampliar DelegatingHandler El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. SendAsync method. Este método me permite inspeccionar la solicitud y devolver una respuesta basada en la solicitud.

public class UmamiDataDelegatingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var absPath = request.RequestUri.AbsolutePath;
        switch (absPath)
        {
            case "/api/auth/login":
                var authContent = await request.Content.ReadFromJsonAsync<AuthRequest>(cancellationToken);
                if (authContent?.username == "username" && authContent?.password == "password")
                    return ReturnAuthenticatedMessage();
                else if (authContent?.username == "bad")
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }
                else
                {
                    return new HttpResponseMessage(HttpStatusCode.BadRequest);
                }
            default:

                if (absPath.StartsWith($"/api/websites/{Consts.WebSiteId}/pageviews"))
                {
                    var pageViews = GetParams<PageViewsRequest> (request);
                  
                    return ReturnPageViewsMessage(pageViews);
                }

                if (absPath.StartsWith($"/api/websites/{Consts.WebSiteId}/metrics"))
                {
                    var metricsRequest = GetParams<MetricsRequest>(request);
                    return ReturnMetrics(metricsRequest);
                }

                return new HttpResponseMessage(HttpStatusCode.NotFound);
        }
    }
 }

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

En el párrafo 2 de la parte dispositiva del proyecto de resolución, la Asamblea General pidió al Secretario General que le presentara en su quincuagésimo séptimo período de sesiones un informe sobre los progresos realizados en la aplicación de la presente resolución. UmamiDataService para usar este handler es similarmente simple.

    public IServiceProvider GetServiceProvider (string username="username", string password="password")
    {
        var services = new ServiceCollection();
        var mockLogger = new FakeLogger<UmamiDataService>();
        var authLogger = new FakeLogger<AuthService>();
        services.AddScoped<ILogger<UmamiDataService>>(_ => mockLogger);
        services.AddScoped<ILogger<AuthService>>(_ => authLogger);
        services.SetupUmamiData(username, password);
        return  services.BuildServiceProvider();
        
    }

En la misma sesión, el Consejo aprobó el proyecto de resolución A/C.1/60/L.20 sin someterlo a votación (véase párr. ServiceCollectionEl Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la eliminación del trabajo forzoso. FakeLogger<T> El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. el último artículo para detalles sobre esto El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiData servicio con el nombre de usuario y contraseña que quiero usar (de modo que podo comprobar el fallo).

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. services.SetupUmamiData(username, password); que es un método de extensión que he creado para configurar el UmamiDataService El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiDataDelegatingHandler El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService;

    public static void SetupUmamiData(this IServiceCollection services, string username="username", string password="password")
    {
        var umamiSettings = new UmamiDataSettings()
        {
            UmamiPath = Consts.UmamiPath,
            Username = username,
            Password = password,
            WebsiteId = Consts.WebSiteId
        };
        services.AddSingleton(umamiSettings);
        services.AddHttpClient<AuthService>((provider,client) =>
        {
            client.BaseAddress = new Uri(umamiSettings.UmamiPath);
            

        }).AddHttpMessageHandler<UmamiDataDelegatingHandler>()
            .SetHandlerLifetime(TimeSpan.FromMinutes(5));  //Set lifetime to five minutes

        services.AddScoped<UmamiDataDelegatingHandler>();
        services.AddScoped<UmamiDataService>();
    }

Usted puede ver que esto es donde me adhiero al UmamiDataDelegatingHandler El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiDataServiceEl Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la adopción de medidas legislativas, administrativas, judiciales y de otra índole. HttpClient El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiDataService El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService para hacer las llamadas a la API de Umami con el bearer El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. BaseAddress En el párrafo 6 de su resolución 57/270 B, la Asamblea General pidió al Secretario General que le presentara en su quincuagésimo séptimo período de sesiones un informe sobre los progresos realizados en la aplicación del Programa de Acción para prevenir, combatir y eliminar todas las formas de discriminación contra la mujer.

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

Realmente esto hace realmente probar este realmente sencillo. Es' es un poco verboso como yo también quería probar el registro también . Todo lo que está haciendoM SK3 es publicar a través de mi DelegatingHandler y simulo una respuesta basada en la solicitud.

public class UmamiData_PageViewsRequest_Test : UmamiDataBase
{
    private readonly DateTime StartDate = DateTime.ParseExact("2021-10-01", "yyyy-MM-dd", null);
    private readonly DateTime EndDate = DateTime.ParseExact("2021-10-07", "yyyy-MM-dd", null);
    
    [Fact]
    public async Task SetupTest_Good()
    {
        var serviceProvider = GetServiceProvider();
        var umamiDataService = serviceProvider.GetRequiredService<UmamiDataService>();
        var authLogger = serviceProvider.GetRequiredService<ILogger<AuthService>>();
        var umamiDataLogger = serviceProvider.GetRequiredService<ILogger<UmamiDataService>>();
        var result = await umamiDataService.GetPageViews(StartDate, EndDate);
        var fakeAuthLogger = (FakeLogger<AuthService>)authLogger;
        FakeLogCollector collector = fakeAuthLogger.Collector; 
        IReadOnlyList<FakeLogRecord> logs = collector.GetSnapshot();
        Assert.Contains("Login successful", logs.Select(x => x.Message));
        
        var fakeUmamiDataLogger = (FakeLogger<UmamiDataService>)umamiDataLogger;
        FakeLogCollector umamiDataCollector = fakeUmamiDataLogger.Collector;
        IReadOnlyList<FakeLogRecord> umamiDataLogs = umamiDataCollector.GetSnapshot();
        Assert.Contains("Successfully got page views", umamiDataLogs.Select(x => x.Message));
        
        Assert.NotNull(result);
    }
}

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

Para simular la respuesta para este método usted' le recordará que tengo esta línea en el UmamiDataDelegatingHandler:

  if (absPath.StartsWith($"/api/websites/{Consts.WebSiteId}/pageviews"))
                {
                    var pageViews = GetParams<PageViewsRequest> (request);
                  
                    return ReturnPageViewsMessage(pageViews);
                }

Todo esto hace es extraer información de la cadena de consulta y construye una respuesta 'realistaM SK1 basada en pruebas de vivo I've compiled , otra vez muy pocas fichas en esta SSK5 UstedMSC6verás que testo para el número de días entre la fecha de inicio y la fecha final y luego devolveré una respuesta con el mismo número de dias

    private static HttpResponseMessage ReturnPageViewsMessage(PageViewsRequest request)
    {
        var startAt = request.StartAt;
        var endAt = request.EndAt;
        var startDate = DateTimeOffset.FromUnixTimeMilliseconds(startAt).DateTime;
        var endDate = DateTimeOffset.FromUnixTimeMilliseconds(endAt).DateTime;
        var days = (endDate - startDate).Days;

        var pageViewsList = new List<PageViewsResponseModel.Pageviews>();
        var sessionsList = new List<PageViewsResponseModel.Sessions>();
        for(int i=0; i<days; i++)
        {
            
            pageViewsList.Add(new PageViewsResponseModel.Pageviews()
            {
                x = startDate.AddDays(i).ToString("yyyy-MM-dd"),
                y = i*4
            });
            sessionsList.Add(new PageViewsResponseModel.Sessions()
            {
                x = startDate.AddDays(i).ToString("yyyy-MM-dd"),
                y = i*8
            });
        }
        var pageViewResponse = new PageViewsResponseModel()
        {
            pageviews = pageViewsList.ToArray(),
            sessions = sessionsList.ToArray()
        };
        var json = JsonSerializer.Serialize(pageViewResponse);
        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(json, Encoding.UTF8, "application/json")
        };
    }

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

Así que ' es realmente ' es bastante sencillo probar un HttpClient la solicitud sin usar Moq y creo que es' es mucho más limpio de esta manera. pierdes una parte de la sofisticación posible en Moq pero para pruebas simples como ésta , Creo que es

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.