GFramework/GFramework.Core.Tests/logging/AsyncLogAppenderTests.cs
GeWuYou abdf4cc690 test(logging): 添加日志系统单元测试
- 为 AsyncLogAppender 添加完整功能测试,包括异步写入、缓冲区管理、并发处理等场景
- 为 CachedLoggerFactory 添加缓存机制测试,验证相同名称和级别的日志记录器重用
- 为 CompositeFilter 添加过滤器组合测试,验证多个过滤器的逻辑组合功能
- 为 CompositeLogger 添加复合日志记录器测试,验证多追加器写入和级别过滤功能
- 为 ConsoleAppender 添加控制台追加器测试,验证格式化输出和过滤器支持
- 为 DefaultLogFormatter 添加默认格式化器测试,验证基本格式化和异常处理功能
- 为 FileAppender 添加文件追加器测试,验证文件写入、目录创建和追加模式功能
- 为 JsonLogFormatter 添加 JSON 格式化器测试,验证 JSON 输出和属性序列化功能
- 为 LogContext 添加日志上下文测试,验证属性推送和作用域管理功能
2026-02-26 19:57:42 +08:00

219 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.logging;
using GFramework.Core.logging.appenders;
using NUnit.Framework;
namespace GFramework.Core.Tests.logging;
/// <summary>
/// 测试 AsyncLogAppender 的功能和行为
/// </summary>
[TestFixture]
public class AsyncLogAppenderTests
{
[Test]
public void Constructor_WithNullInnerAppender_ShouldThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => new AsyncLogAppender(null!));
}
[Test]
public void Constructor_WithInvalidBufferSize_ShouldThrowArgumentException()
{
var innerAppender = new TestAppender();
Assert.Throws<ArgumentException>(() => new AsyncLogAppender(innerAppender, bufferSize: 0));
Assert.Throws<ArgumentException>(() => new AsyncLogAppender(innerAppender, bufferSize: -1));
}
[Test]
public void Append_ShouldNotBlock()
{
var innerAppender = new SlowAppender(delayMs: 100);
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
var startTime = DateTime.Now;
for (int i = 0; i < 10; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
// 异步写入应该非常快(< 100ms不应该等待内部 Appender
Assert.That(elapsed, Is.LessThan(100));
}
[Test]
public void Append_ShouldEventuallyWriteToInnerAppender()
{
var innerAppender = new TestAppender();
using (var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000))
{
for (int i = 0; i < 10; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
asyncAppender.Flush();
}
Assert.That(innerAppender.Entries.Count, Is.EqualTo(10));
}
[Test]
public void Flush_ShouldWaitForAllEntriesToBeProcessed()
{
var innerAppender = new TestAppender();
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
for (int i = 0; i < 100; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
asyncAppender.Flush();
Assert.That(innerAppender.Entries.Count, Is.EqualTo(100));
}
[Test]
public void Dispose_ShouldProcessRemainingEntries()
{
var innerAppender = new TestAppender();
using (var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000))
{
for (int i = 0; i < 50; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
} // Dispose 会等待所有日志处理完成
Assert.That(innerAppender.Entries.Count, Is.EqualTo(50));
}
[Test]
public void Append_AfterDispose_ShouldThrowObjectDisposedException()
{
var innerAppender = new TestAppender();
var asyncAppender = new AsyncLogAppender(innerAppender);
asyncAppender.Dispose();
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", "Test", null, null);
Assert.Throws<ObjectDisposedException>(() => asyncAppender.Append(entry));
}
[Test]
public void PendingCount_ShouldReflectQueuedEntries()
{
var innerAppender = new SlowAppender(delayMs: 50);
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
for (int i = 0; i < 10; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
// 应该有一些待处理的条目
Assert.That(asyncAppender.PendingCount, Is.GreaterThanOrEqualTo(0));
}
[Test]
public async Task Append_FromMultipleThreads_ShouldHandleConcurrency()
{
var innerAppender = new TestAppender();
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 10000);
var tasks = new Task[10];
for (int t = 0; t < 10; t++)
{
int threadId = t;
tasks[t] = Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger",
$"Thread {threadId} Message {i}", null, null);
asyncAppender.Append(entry);
}
});
}
await Task.WhenAll(tasks);
asyncAppender.Flush();
Assert.That(innerAppender.Entries.Count, Is.EqualTo(1000));
}
[Test]
public void Append_WhenInnerAppenderThrows_ShouldNotCrash()
{
var innerAppender = new ThrowingAppender();
using var asyncAppender = new AsyncLogAppender(innerAppender, bufferSize: 1000);
// 即使内部 Appender 抛出异常,也不应该影响调用线程
Assert.DoesNotThrow(() =>
{
for (int i = 0; i < 10; i++)
{
var entry = new LogEntry(DateTime.Now, LogLevel.Info, "TestLogger", $"Message {i}", null, null);
asyncAppender.Append(entry);
}
});
Thread.Sleep(100); // 等待后台处理
}
// 辅助测试类
private class TestAppender : ILogAppender
{
public List<LogEntry> Entries { get; } = new();
public void Append(LogEntry entry)
{
lock (Entries)
{
Entries.Add(entry);
}
}
public void Flush()
{
}
}
private class SlowAppender : ILogAppender
{
private readonly int _delayMs;
public SlowAppender(int delayMs)
{
_delayMs = delayMs;
}
public void Append(LogEntry entry)
{
Thread.Sleep(_delayMs);
}
public void Flush()
{
}
}
private class ThrowingAppender : ILogAppender
{
public void Append(LogEntry entry)
{
throw new InvalidOperationException("Test exception");
}
public void Flush()
{
}
}
}