using System.Collections.Generic;
using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json.Linq;
namespace Dpz.Core.ServiceTest;
[TestFixture]
public class AppLogEntryServiceTest
{
private const int Top = 10;
private const int TooManyRequestsStatusCode = 429;
private static readonly string[] RequestLogFilters =
[
"Program = 'Dpz.Core.Web'",
"SourceContext = 'Serilog.AspNetCore.RequestLoggingMiddleware'",
];
[Test]
public async Task GetPageAsync_ShouldReturnRequestLogs()
{
var service = CreateService();
var pageSize = 10;
var part = await service.GetPageAsync(BuildRequestLogFilter(), pageSize: pageSize);
Assert.That(part, Is.Not.Null);
Assert.That(part?.Events, Is.Not.Null);
Assert.That(part?.Events, Is.Not.Empty);
Assert.That(part?.Events.Count, Is.LessThanOrEqualTo(pageSize));
}
[Test]
public async Task GetLatestAccessNumberAsync_ShouldReturnRecentDailyAccessSummary()
{
var service = CreateService();
var accessNumbers = await service.GetLatestAccessNumberAsync(-7);
Assert.That(accessNumbers, Is.Not.Null);
Assert.That(accessNumbers, Is.Not.Empty);
foreach (var item in accessNumbers)
{
Assert.That(
DateTime.TryParseExact(
item.Date,
"yyyy/MM/dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out _
),
Is.True
);
Assert.That(item.Count, Is.GreaterThanOrEqualTo(0));
}
}
[Test]
public async Task GetAccessStatisticsAsync_ShouldReturnSummaryDimensions()
{
var service = CreateService();
var statistics = await service.GetAccessStatisticsAsync(days: 7, top: Top);
Assert.That(statistics, Is.Not.Null);
Assert.That(statistics.PopularPages, Is.Not.Empty);
Assert.That(statistics.HourlyTraffic, Is.Not.Empty);
Assert.That(statistics.BrowserUsage, Is.Not.Empty);
Assert.That(statistics.SlowRequests.Count, Is.LessThanOrEqualTo(Top));
Assert.That(statistics.PopularPages.Count, Is.LessThanOrEqualTo(Top));
Assert.That(statistics.BrowserUsage.Count, Is.LessThanOrEqualTo(Top));
Assert.That(statistics.Referers.Count, Is.LessThanOrEqualTo(Top));
foreach (var item in statistics.SlowRequests)
{
Assert.That(item.StatusCode, Is.Not.EqualTo(TooManyRequestsStatusCode));
Assert.That(
DateTime.TryParseExact(
item.Time,
"yyyy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out var recordTime
),
Is.True
);
Assert.That(recordTime.Hour == 6 && recordTime.Minute < 30, Is.False);
}
foreach (var item in statistics.PopularPages)
{
Assert.That(item.RequestPath, Is.Not.Empty);
Assert.That(item.Count, Is.GreaterThanOrEqualTo(0));
}
foreach (var item in statistics.HourlyTraffic)
{
Assert.That(
DateTime.TryParseExact(
item.Date,
"yyyy/MM/dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out _
),
Is.True
);
Assert.That(item.Hour, Is.InRange(0, 23));
Assert.That(item.Count, Is.GreaterThanOrEqualTo(0));
}
foreach (var item in statistics.BrowserUsage)
{
Assert.That(item.Browser, Is.Not.Empty);
Assert.That(item.Count, Is.GreaterThanOrEqualTo(0));
Assert.That(item.Percentage, Is.InRange(0m, 100m));
}
foreach (var item in statistics.Referers)
{
Assert.That(item.Referer, Is.Not.Empty);
Assert.That(item.Count, Is.GreaterThanOrEqualTo(0));
}
}
[Test]
public void NormalizeString_ShouldReadNewtonsoftJsonValue()
{
var method = typeof(AppLogEntryService).GetMethod(
"NormalizeString",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static
);
Assert.That(method, Is.Not.Null);
Assert.That(
method!.Invoke(null, [new JValue("https://example.com")]),
Is.EqualTo("https://example.com")
);
Assert.That(method.Invoke(null, [JValue.CreateNull()]), Is.Null);
}
private static IAppLogEntryService CreateService()
{
var configuration = CreateConfiguration();
return new AppLogEntryService(configuration, NullLogger<AppLogEntryService>.Instance);
}
private static IConfiguration CreateConfiguration() =>
new ConfigurationBuilder().AddJsonFile("appsettings.Test.json").Build();
private static string BuildRequestLogFilter() => string.Join(" and ", RequestLogFilters);
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码说明
这是一个针对 AppLogEntryService 的单元测试类,用于测试应用程序日志条目服务的功能。该测试使用 NUnit 测试框架。
主要组成部分
常量定义
- Top: 设置为 10,用于限制查询返回的记录数
- TooManyRequestsStatusCode: HTTP 429 状态码(请求过多)
- RequestLogFilters: 请求日志过滤条件数组,筛选来自特定程序和上下文的日志
测试方法
1. GetPageAsync_ShouldReturnRequestLogs
测试分页获取请求日志的功能:
- 创建服务实例
- 调用
GetPageAsync方法获取指定页面大小的日志 - 验证返回结果不为空,有数据,且数量不超过指定的页面大小
2. GetLatestAccessNumberAsync_ShouldReturnRecentDailyAccessSummary
测试获取最近访问次数统计的功能:
- 获取最近 7 天的访问统计数据
- 验证返回的数据:
- 日期格式正确(
yyyy/MM/dd) - 访问计数大于等于 0
- 日期格式正确(
3. GetAccessStatisticsAsync_ShouldReturnSummaryDimensions
这是最复杂的测试,验证访问统计的多维度数据:
- 获取 7 天内的统计信息
- 验证多个维度的数据:
- 慢请求:验证状态码不是 429,时间格式正确,排除特定时间段(6:00-6:30)
- 热门页面:验证请求路径和访问次数
- 每小时流量:验证日期格式、小时范围(0-23)和计数
- 浏览器使用情况:验证浏览器名称、计数和百分比(0-100%)
- 来源引用:验证引用地址和计数
- 所有列表的长度都不超过
Top常量(10)
4. NormalizeString_ShouldReadNewtonsoftJsonValue
测试 AppLogEntryService 类中的私有静态方法 NormalizeString:
- 使用反射获取私有方法
- 测试该方法能正确处理 Newtonsoft.Json 的
JValue对象 - 验证字符串值的正常化和 null 值处理
辅助方法
- CreateService(): 创建
AppLogEntryService实例,使用配置和空日志记录器 - CreateConfiguration(): 从
appsettings.Test.json文件加载测试配置 - BuildRequestLogFilter(): 将过滤条件数组连接成查询字符串(用 "and" 连接)
测试目的
该测试套件全面验证了日志服务的核心功能,包括:
- 数据检索和分页
- 统计分析(访问量、热门页面、流量分布等)
- 数据格式和范围验证
- 边界条件检查
AI 正在分析代码…
评论加载中...