GFramework/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs
GeWuYou eec50ab45b feat(events): 添加事件上下文支持和线程安全改进
- 在EventBus中添加RegisterWithContext方法支持事件上下文
- 实现EventContext<T>类包装事件数据并提供处理控制
- 在PriorityEvent中添加上下文事件处理器和相关管理逻辑
- 改进事件触发机制支持普通和上下文处理器混合使用
- 优化MicrosoftDiContainer的线程安全性和并发访问
- 修复SpanExtensions中TryParseValue的返回值类型问题
- 添加全面的单元测试覆盖新功能和边界情况
2026-02-25 21:39:53 +08:00

452 lines
13 KiB
C#

using System.Reflection;
using GFramework.Core.ioc;
using GFramework.Core.logging;
using GFramework.Core.Tests.system;
using NUnit.Framework;
namespace GFramework.Core.Tests.ioc;
/// <summary>
/// 测试 IoC 容器功能的单元测试类
/// </summary>
[TestFixture]
public class MicrosoftDiContainerTests
{
/// <summary>
/// 在每个测试方法执行前进行设置
/// </summary>
[SetUp]
public void SetUp()
{
// 初始化 LoggerFactoryResolver 以支持 MicrosoftDiContainer
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
_container = new MicrosoftDiContainer();
// 直接初始化 logger 字段
var loggerField = typeof(MicrosoftDiContainer).GetField("_logger",
BindingFlags.NonPublic | BindingFlags.Instance);
loggerField?.SetValue(_container,
LoggerFactoryResolver.Provider.CreateLogger(nameof(MicrosoftDiContainer)));
}
private MicrosoftDiContainer _container = null!;
/// <summary>
/// 测试注册单例实例的功能
/// </summary>
[Test]
public void RegisterSingleton_Should_Register_Instance()
{
var instance = new TestService();
Assert.DoesNotThrow(() => _container.RegisterSingleton(instance));
}
/// <summary>
/// 测试重复注册单例时应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void RegisterSingleton_WithDuplicate_Should_ThrowInvalidOperationException()
{
var instance1 = new TestService();
var instance2 = new TestService();
_container.RegisterSingleton(instance1);
Assert.Throws<InvalidOperationException>(() => _container.RegisterSingleton(instance2));
}
/// <summary>
/// 测试在容器冻结后注册单例时应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void RegisterSingleton_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.RegisterSingleton(instance));
}
/// <summary>
/// 测试注册多样性实例到所有类型的功能
/// </summary>
[Test]
public void RegisterPlurality_Should_Register_Instance_To_All_Types()
{
var instance = new TestService();
_container.RegisterPlurality(instance);
Assert.That(_container.Contains<TestService>(), Is.True);
Assert.That(_container.Contains<IService>(), Is.True);
}
/// <summary>
/// 测试在容器冻结后注册多样性实例时应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void RegisterPlurality_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.RegisterPlurality(instance));
}
/// <summary>
/// 测试泛型注册实例的功能
/// </summary>
[Test]
public void Register_Generic_Should_Register_Instance()
{
var instance = new TestService();
_container.Register(instance);
Assert.That(_container.Contains<TestService>(), Is.True);
}
/// <summary>
/// 测试在容器冻结后使用泛型注册时应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void Register_Generic_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.Register(instance));
}
/// <summary>
/// 测试按类型注册实例的功能
/// </summary>
[Test]
public void Register_Type_Should_Register_Instance()
{
var instance = new TestService();
_container.Register(typeof(TestService), instance);
Assert.That(_container.Contains<TestService>(), Is.True);
}
/// <summary>
/// 测试获取第一个实例的功能
/// </summary>
[Test]
public void Get_Should_Return_First_Instance()
{
var instance = new TestService();
_container.Register(instance);
var result = _container.Get<TestService>();
Assert.That(result, Is.Not.Null);
Assert.That(result, Is.SameAs(instance));
}
/// <summary>
/// 测试当没有实例时获取应返回 null 的功能
/// </summary>
[Test]
public void Get_WithNoInstances_Should_ReturnNull()
{
var result = _container.Get<TestService>();
Assert.That(result, Is.Null);
}
/// <summary>
/// 测试获取必需的单个实例的功能
/// </summary>
[Test]
public void GetRequired_Should_Return_Single_Instance()
{
var instance = new TestService();
_container.Register(instance);
var result = _container.GetRequired<TestService>();
Assert.That(result, Is.Not.Null);
Assert.That(result, Is.SameAs(instance));
}
/// <summary>
/// 测试当没有实例时获取必需实例应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void GetRequired_WithNoInstances_Should_ThrowInvalidOperationException()
{
Assert.Throws<InvalidOperationException>(() => _container.GetRequired<TestService>());
}
/// <summary>
/// 测试当有多个实例时获取必需实例应抛出 InvalidOperationException 异常
/// </summary>
[Test]
public void GetRequired_WithMultipleInstances_Should_ThrowInvalidOperationException()
{
_container.Register(new TestService());
_container.Register(new TestService());
Assert.Throws<InvalidOperationException>(() => _container.GetRequired<TestService>());
}
/// <summary>
/// 测试获取所有实例的功能
/// </summary>
[Test]
public void GetAll_Should_Return_All_Instances()
{
var instance1 = new TestService();
var instance2 = new TestService();
_container.Register(instance1);
_container.Register(instance2);
var results = _container.GetAll<TestService>();
Assert.That(results.Count, Is.EqualTo(2));
Assert.That(results, Does.Contain(instance1));
Assert.That(results, Does.Contain(instance2));
}
/// <summary>
/// 测试当没有实例时获取所有实例应返回空数组的功能
/// </summary>
[Test]
public void GetAll_WithNoInstances_Should_Return_Empty_Array()
{
var results = _container.GetAll<TestService>();
Assert.That(results.Count, Is.EqualTo(0));
}
/// <summary>
/// 测试获取排序后的所有实例的功能
/// </summary>
[Test]
public void GetAllSorted_Should_Return_Sorted_Instances()
{
_container.Register(new TestService { Priority = 3 });
_container.Register(new TestService { Priority = 1 });
_container.Register(new TestService { Priority = 2 });
var results = _container.GetAllSorted<TestService>((a, b) => a.Priority.CompareTo(b.Priority));
Assert.That(results.Count, Is.EqualTo(3));
Assert.That(results[0].Priority, Is.EqualTo(1));
Assert.That(results[1].Priority, Is.EqualTo(2));
Assert.That(results[2].Priority, Is.EqualTo(3));
}
/// <summary>
/// 测试当存在实例时检查包含关系应返回 true 的功能
/// </summary>
[Test]
public void Contains_WithExistingInstance_Should_ReturnTrue()
{
// 使用 RegisterSingleton 方法来避免与其他测试方法重复
var instance = new TestService();
_container.RegisterSingleton(instance);
// 验证容器包含该实例
Assert.That(_container.Contains<TestService>(), Is.True);
// 验证实例确实是单例
Assert.That(_container.Get<TestService>(), Is.SameAs(instance));
}
/// <summary>
/// 测试当不存在实例时检查包含关系应返回 false 的功能
/// </summary>
[Test]
public void Contains_WithNoInstances_Should_ReturnFalse()
{
Assert.That(_container.Contains<TestService>(), Is.False);
}
/// <summary>
/// 测试当实例存在时检查实例包含关系应返回 true 的功能
/// </summary>
[Test]
public void ContainsInstance_WithExistingInstance_Should_ReturnTrue()
{
var instance = new TestService();
_container.Register(instance);
Assert.That(_container.ContainsInstance(instance), Is.True);
}
/// <summary>
/// 测试当实例不存在时检查实例包含关系应返回 false 的功能
/// </summary>
[Test]
public void ContainsInstance_WithNonExistingInstance_Should_ReturnFalse()
{
var instance = new TestService();
Assert.That(_container.ContainsInstance(instance), Is.False);
}
/// <summary>
/// 测试清除所有实例的功能
/// </summary>
[Test]
public void Clear_Should_Remove_All_Instances()
{
var instance = new TestService();
_container.Register(instance);
_container.Clear();
Assert.That(_container.Contains<TestService>(), Is.False);
}
/// <summary>
/// 测试冻结容器以防止进一步注册的功能
/// </summary>
[Test]
public void Freeze_Should_Prevent_Further_Registrations()
{
var instance1 = new TestService();
_container.Register(instance1);
_container.Freeze();
var instance2 = new TestService();
Assert.Throws<InvalidOperationException>(() => _container.Register(instance2));
}
/// <summary>
/// 测试注册系统实例的功能
/// </summary>
[Test]
public void RegisterSystem_Should_Register_Instance()
{
var system = new TestSystem();
_container.RegisterSystem(system);
Assert.That(_container.Contains<TestSystem>(), Is.True);
}
/// <summary>
/// 测试在容器未冻结时调用 CreateScope 应抛出异常
/// </summary>
[Test]
public void CreateScope_Should_Throw_When_Not_Frozen()
{
// Arrange
var container = new MicrosoftDiContainer();
// Act & Assert
Assert.Throws<InvalidOperationException>(() => container.CreateScope());
}
/// <summary>
/// 测试 CreateScope 在多线程环境下的线程安全性
/// </summary>
[Test]
public void CreateScope_Should_Be_Thread_Safe()
{
// Arrange
var container = new MicrosoftDiContainer();
container.RegisterSingleton<IService>(new TestService());
container.Freeze();
// Act
var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() =>
{
using var scope = container.CreateScope();
Assert.That(scope, Is.Not.Null);
})).ToArray();
// Assert
Assert.DoesNotThrow(() => Task.WaitAll(tasks));
}
/// <summary>
/// 测试 Get 方法在多线程环境下的线程安全性
/// </summary>
[Test]
public void Get_Should_Be_Thread_Safe()
{
// Arrange
var container = new MicrosoftDiContainer();
container.RegisterSingleton<IService>(new TestService());
container.Freeze();
// Act
var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() =>
{
var service = container.Get<IService>();
Assert.That(service, Is.Not.Null);
})).ToArray();
// Assert
Assert.DoesNotThrow(() => Task.WaitAll(tasks));
}
/// <summary>
/// 测试 GetAll 方法在多线程环境下的线程安全性
/// </summary>
[Test]
public void GetAll_Should_Be_Thread_Safe()
{
// Arrange
var container = new MicrosoftDiContainer();
container.RegisterSingleton<IService>(new TestService());
container.Freeze();
// Act
var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() =>
{
var services = container.GetAll<IService>();
Assert.That(services, Is.Not.Null);
})).ToArray();
// Assert
Assert.DoesNotThrow(() => Task.WaitAll(tasks));
}
/// <summary>
/// 测试 Contains 方法在多线程环境下的线程安全性
/// </summary>
[Test]
public void Contains_Should_Be_Thread_Safe()
{
// Arrange
var container = new MicrosoftDiContainer();
container.RegisterSingleton<IService>(new TestService());
container.Freeze();
// Act
var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() =>
{
var contains = container.Contains<IService>();
Assert.That(contains, Is.True);
})).ToArray();
// Assert
Assert.DoesNotThrow(() => Task.WaitAll(tasks));
}
}
/// <summary>
/// 服务接口定义
/// </summary>
public interface IService;
/// <summary>
/// 测试服务类,实现 IService 接口
/// </summary>
public sealed class TestService : IService
{
/// <summary>
/// 获取或设置优先级
/// </summary>
public int Priority { get; set; }
}