# اختبار وحدة Umami.Net - التسجيل في ASPM SK2NET Core

# المقدمة

أنا 'أنا نُوِب نسبي يستعمل موك (نعم أنا ♫' ♫أنا أدرك المناقشات ♫ ) ♫ وكنت أحاول اختبار خدمة جديدة أنا ♪ ' ♫ أضيف إلى أومامي ♪. ♫ شبكة ♪

[TOC]

<!--category-- xUnit, ASP.NET Core -->
<datetime class="hidden">2024-09-04T13:22</datetime>

# المشكلة

كنت أحاول أن أضيف اختباراً بسيطاً للصفة الإتصالية التي أريد أن أستخدمها عندما أسحب البيانات.
كما ترون، ' هو خدمة بسيطة تنقل اسم пользователя وكلمة مرور إلى `/api/auth/login` نقطة النهاية وتحصل على النتيجة. إذا كان النتيجة ناجحة فإنه يحفظ الرموز في `_token` و يضع الحقل `Authorization` عنوان لـ `HttpClient` لتستخدم في الطلبات المستقبلية.

```csharp
public class AuthService(HttpClient httpClient, UmamiDataSettings umamiSettings, ILogger<AuthService> logger)
{
    private string _token = string.Empty;
    public HttpClient HttpClient => httpClient;

    public async Task<bool> LoginAsync()
    {
        var loginData = new
        {
            username = umamiSettings.Username,
            password = umamiSettings.Password
        };

        var content = new StringContent(JsonSerializer.Serialize(loginData), Encoding.UTF8, "application/json");
        var response = await httpClient.PostAsync("/api/auth/login", content);

        if (response.IsSuccessStatusCode)
        {
            var authResponse = await response.Content.ReadFromJsonAsync<AuthResponse>();

            if (authResponse == null)
            {
                logger.LogError("Login failed");
                return false;
            }

            _token = authResponse.Token;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
            logger.LogInformation("Login successful");
            return true;
        }

        logger.LogError("Login failed");
        return false;
    }
}
```

الآن أردت أيضا أن أختبر ضد المسجل للتأكد من أنه يسجل الرسائل الصحيحة `Microsoft.Extensions.Logging` و أردت أن أختبر أن رسائل الملاحظات الصحيحة كانت تُكتب إلى الملاحظ

في موك هناك ' مجموعة من المدونات حول اختبار السجل لديهم جميعهم هذا الشكل الأساسي ( من "https"

```csharp
public static Mock<ILogger<T>> VerifyDebugWasCalled<T>(this Mock<ILogger<T>> logger, string expectedMessage)
{
    Func<object, Type, bool> state = (v, t) => v.ToString().CompareTo(expectedMessage) == 0;
    
    logger.Verify(
        x => x.Log(
            It.Is<LogLevel>(l => l == LogLevel.Debug),
            It.IsAny<EventId>(),
            It.Is<It.IsAnyType>((v, t) => state(v, t)),
            It.IsAny<Exception>(),
            It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)));

    return logger;
}
```

على الرغم من تغيرات "Moq" و ' مؤخراً، ( "It" "MSC2" "IsAnyType" قديمة الآن "M SK3" "ASP" . "NET Core" ' تغييرات "FormattedLogValues" كان لدي الكثير من الوقت لجعل هذا يعمل"

حاولت مجموعة من الإصدارات والمتغيرات لكنها دائماً فشلت

# الحل

لذا فقراءة مجموعة من رسائل GitHub صادفت رسالة من ديفيد فوولر (زميلي السابق والآن رب .NET) التي أظهرت طريقة بسيطة لاختبار السجل في ASP
هذا يستخدم *جديد بالنسبة لي* `Microsoft.Extensions.Diagnostics.Testing` [حزمة](https://github.com/dotnet/extensions/tree/main/src/Libraries/Microsoft.Extensions.Diagnostics.Testing) الذي يحتوي على بعض الإضافات المفيدة حقاً لاختبار السجل

فبدلاً من كل الأشياء الموكية قمت بإضافة `Microsoft.Extensions.Diagnostics.Testing` و أضافت التالي إلى إختباراتي.

```csharp
    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();
        
    }
```

ستلاحظون أن هذا يضع مجموع خدماتي `FakeLogger<T>` ومن ثم يقوم بإعداد `UmamiData` خدمة مع username وパスワード أريد أن أستخدم (لذلك أستطيع إختبار الفشل).

## الإختبارات باستخدام FakeLogger

ثم يمكن لاختباراتي أن تصبح :

```csharp
    [Fact]
    public async Task SetupTest_Good()
    {
        var serviceProvider = GetServiceProvider();
        var authService = serviceProvider.GetRequiredService<AuthService>();
        var authLogger = serviceProvider.GetRequiredService<ILogger<AuthService>>();
        var result = await authService.LoginAsync();
        var fakeLogger = (FakeLogger<AuthService>)authLogger;
        FakeLogCollector collector = fakeLogger.Collector; // Collector allows you to access the captured logs
         IReadOnlyList<FakeLogRecord> logs = collector.GetSnapshot();
         Assert.Contains("Login successful", logs.Select(x => x.Message));
        Assert.True(result);
    }
```

حيث سترى ' سأتصل ببساطة `GetServiceProvider` طريقة للحصول على مزود خدماتي, ثم الحصول على `AuthService` و `ILogger<AuthService>` من مقدم الخدمة.

لأنني وضعت هذه كـ `FakeLogger<T>` ومن ثم يمكنني الوصول إلى `FakeLogCollector` و `FakeLogRecord` للحصول على الملاحظات والتحقق منها.

عندها أستطيع ببساطة فحص الملاحظات للرسال الصحيحة.

# في الختام

إذاً هناك لديكه, طريقة بسيطة لاختبار رسائل الملاحظات في إختبارات وحدة بدون مزخرفة Moq.