test(core): 添加核心组件单元测试并优化目标框架配置

- 在AsyncTestModel和TestModel中添加override关键字修复方法重写
- 调整GFramework.Core.Tests和GFramework.SourceGenerators.Tests的目标框架顺序为net10.0;net8.0
- 优化SyncArchitectureTests中的注释格式,统一添加前导空格
- 移除TestQuery相关代码文件
- 新增BindablePropertyTests测试绑定属性功能
- 新增CommandBusTests测试命令总线功能
- 新增EasyEventsTests和EventTests测试事件系统功能
- 新增IocContainerTests测试依赖注入容器功能
- 新增ObjectExtensionsTests测试对象扩展方法功能
- 新增ObjectPoolTests测试对象池功能
- 新增OrEventTests测试或事件功能
- 新增QueryBusTests测试查询总线功能
- [skip ci]
This commit is contained in:
GeWuYou 2026-01-15 13:53:08 +08:00
parent 3ec1c6748b
commit dda2d8f864
15 changed files with 1143 additions and 38 deletions

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1"/>

View File

@ -0,0 +1,88 @@
using GFramework.Core.Abstractions.command;
using GFramework.Core.command;
using NUnit.Framework;
namespace GFramework.Core.Tests.command;
[TestFixture]
public class CommandBusTests
{
[SetUp]
public void SetUp()
{
_commandBus = new CommandBus();
}
private CommandBus _commandBus = null!;
[Test]
public void Send_Should_Execute_Command()
{
var input = new TestCommandInput { Value = 42 };
var command = new TestCommand(input);
Assert.DoesNotThrow(() => _commandBus.Send(command));
Assert.That(command.Executed, Is.True);
Assert.That(command.ExecutedValue, Is.EqualTo(42));
}
[Test]
public void Send_WithNullCommand_Should_ThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => _commandBus.Send(null!));
}
[Test]
public void Send_WithResult_Should_Return_Value()
{
var input = new TestCommandInput { Value = 100 };
var command = new TestCommandWithResult(input);
var result = _commandBus.Send(command);
Assert.That(command.Executed, Is.True);
Assert.That(result, Is.EqualTo(200));
}
[Test]
public void Send_WithResult_AndNullCommand_Should_ThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => _commandBus.Send<int>(null!));
}
}
public sealed class TestCommandInput : ICommandInput
{
public int Value { get; init; }
}
public sealed class TestCommand : AbstractCommand<TestCommandInput>
{
public TestCommand(TestCommandInput input) : base(input)
{
}
public bool Executed { get; private set; }
public int ExecutedValue { get; private set; }
protected override void OnExecute(TestCommandInput input)
{
Executed = true;
ExecutedValue = 42;
}
}
public sealed class TestCommandWithResult : AbstractCommand<TestCommandInput, int>
{
public TestCommandWithResult(TestCommandInput input) : base(input)
{
}
public bool Executed { get; private set; }
protected override int OnExecute(TestCommandInput input)
{
Executed = true;
return input.Value * 2;
}
}

View File

@ -0,0 +1,50 @@
using GFramework.Core.events;
using NUnit.Framework;
namespace GFramework.Core.Tests.events;
[TestFixture]
public class EasyEventsTests
{
[SetUp]
public void SetUp()
{
_easyEvents = new EasyEvents();
}
private EasyEvents _easyEvents = null!;
[Test]
public void Get_EventT_Should_Trigger_With_Parameter()
{
_easyEvents.GetOrAddEvent<Event<int>>();
var receivedValue = 0;
var @event = EasyEvents.Get<Event<int>>();
@event.Register(value => { receivedValue = value; });
@event.Trigger(42);
Assert.That(receivedValue, Is.EqualTo(42));
}
[Test]
public void Get_EventTTK_Should_Trigger_With_Two_Parameters()
{
_easyEvents.GetOrAddEvent<Event<int, string>>();
var receivedInt = 0;
var receivedString = string.Empty;
var @event = EasyEvents.Get<Event<int, string>>();
@event.Register((i, s) =>
{
receivedInt = i;
receivedString = s;
});
@event.Trigger(100, "hello");
Assert.That(receivedInt, Is.EqualTo(100));
Assert.That(receivedString, Is.EqualTo("hello"));
}
}

View File

@ -0,0 +1,134 @@
using GFramework.Core.events;
using NUnit.Framework;
namespace GFramework.Core.Tests.events;
[TestFixture]
public class EventTests
{
[SetUp]
public void SetUp()
{
_easyEvent = new EasyEvent();
_eventInt = new Event<int>();
_eventIntString = new Event<int, string>();
}
private EasyEvent _easyEvent = null!;
private Event<int> _eventInt = null!;
private Event<int, string> _eventIntString = null!;
[Test]
public void EasyEvent_Register_Should_Add_Handler()
{
var called = false;
_easyEvent.Register(() => { called = true; });
_easyEvent.Trigger();
Assert.That(called, Is.True);
}
[Test]
public void EasyEvent_UnRegister_Should_Remove_Handler()
{
var count = 0;
var handler = () => { count++; };
_easyEvent.Register(handler);
_easyEvent.Trigger();
Assert.That(count, Is.EqualTo(1));
_easyEvent.UnRegister(handler);
_easyEvent.Trigger();
Assert.That(count, Is.EqualTo(1));
}
[Test]
public void EasyEvent_Multiple_Handlers_Should_All_Be_Called()
{
var count1 = 0;
var count2 = 0;
_easyEvent.Register(() => { count1++; });
_easyEvent.Register(() => { count2++; });
_easyEvent.Trigger();
Assert.That(count1, Is.EqualTo(1));
Assert.That(count2, Is.EqualTo(1));
}
[Test]
public void EventT_Register_Should_Add_Handler()
{
var receivedValue = 0;
_eventInt.Register(value => { receivedValue = value; });
_eventInt.Trigger(42);
Assert.That(receivedValue, Is.EqualTo(42));
}
[Test]
public void EventT_UnRegister_Should_Remove_Handler()
{
var count = 0;
Action<int> handler = value => { count++; };
_eventInt.Register(handler);
_eventInt.Trigger(1);
Assert.That(count, Is.EqualTo(1));
_eventInt.UnRegister(handler);
_eventInt.Trigger(2);
Assert.That(count, Is.EqualTo(1));
}
[Test]
public void EventT_Multiple_Handlers_Should_All_Be_Called()
{
var values = new List<int>();
_eventInt.Register(value => { values.Add(value); });
_eventInt.Register(value => { values.Add(value * 2); });
_eventInt.Trigger(5);
Assert.That(values.Count, Is.EqualTo(2));
Assert.That(values, Does.Contain(5));
Assert.That(values, Does.Contain(10));
}
[Test]
public void EventTTK_Register_Should_Add_Handler()
{
var receivedInt = 0;
var receivedString = string.Empty;
_eventIntString.Register((i, s) =>
{
receivedInt = i;
receivedString = s;
});
_eventIntString.Trigger(42, "test");
Assert.That(receivedInt, Is.EqualTo(42));
Assert.That(receivedString, Is.EqualTo("test"));
}
[Test]
public void EventTTK_UnRegister_Should_Remove_Handler()
{
var count = 0;
Action<int, string> handler = (i, s) => { count++; };
_eventIntString.Register(handler);
_eventIntString.Trigger(1, "a");
Assert.That(count, Is.EqualTo(1));
_eventIntString.UnRegister(handler);
_eventIntString.Trigger(2, "b");
Assert.That(count, Is.EqualTo(1));
}
}

View File

@ -0,0 +1,81 @@
using GFramework.Core.events;
using NUnit.Framework;
namespace GFramework.Core.Tests.events;
[TestFixture]
public class OrEventTests
{
[Test]
public void OrEvent_Should_Trigger_When_Any_Event_Fires()
{
var event1 = new Event<int>();
var event2 = new Event<int>();
var orEvent = new OrEvent();
var triggered = false;
orEvent.Register(() => { triggered = true; });
orEvent.Or(event1).Or(event2);
event1.Trigger(0);
Assert.That(triggered, Is.True);
}
[Test]
public void OrEvent_Should_Trigger_When_Second_Event_Fires()
{
var event1 = new Event<int>();
var event2 = new Event<int>();
var orEvent = new OrEvent();
var triggered = false;
orEvent.Register(() => { triggered = true; });
orEvent.Or(event1).Or(event2);
event2.Trigger(0);
Assert.That(triggered, Is.True);
}
[Test]
public void OrEvent_Should_Support_Multiple_Handlers()
{
var @event = new Event<int>();
var orEvent = new OrEvent();
var count1 = 0;
var count2 = 0;
orEvent.Register(() => { count1++; });
orEvent.Register(() => { count2++; });
orEvent.Or(@event);
@event.Trigger(0);
Assert.That(count1, Is.EqualTo(1));
Assert.That(count2, Is.EqualTo(1));
}
[Test]
public void OrEvent_UnRegister_Should_Remove_Handler()
{
var @event = new Event<int>();
var orEvent = new OrEvent();
var count = 0;
var handler = () => { count++; };
orEvent.Register(handler);
orEvent.Or(@event);
@event.Trigger(0);
Assert.That(count, Is.EqualTo(1));
orEvent.UnRegister(handler);
@event.Trigger(0);
Assert.That(count, Is.EqualTo(1));
}
}

View File

@ -0,0 +1,180 @@
using GFramework.Core.extensions;
using NUnit.Framework;
namespace GFramework.Core.Tests.extensions;
[TestFixture]
public class ObjectExtensionsTests
{
[Test]
public void IfType_Should_Execute_Action_When_Type_Matches()
{
var obj = new TestClass();
var executed = false;
obj.IfType<TestClass>(_ => { executed = true; });
Assert.That(executed, Is.True);
}
[Test]
public void IfType_Should_Not_Execute_Action_When_Type_Does_Not_Match()
{
var obj = new TestClass();
var executed = false;
obj.IfType<string>(_ => { executed = true; });
Assert.That(executed, Is.False);
}
[Test]
public void IfType_WithPredicate_Should_Execute_When_Type_Matches_And_Predicate_True()
{
var obj = new TestClass { Value = 10 };
var executed = false;
obj.IfType<TestClass>(x => x.Value > 5, _ => { executed = true; });
Assert.That(executed, Is.True);
}
[Test]
public void IfType_WithPredicate_Should_Not_Execute_When_Predicate_False()
{
var obj = new TestClass { Value = 3 };
var executed = false;
obj.IfType<TestClass>(x => x.Value > 5, _ => { executed = true; });
Assert.That(executed, Is.False);
}
[Test]
public void IfType_WithBoth_Actions_Should_Execute_Correct_Action()
{
var matchCount = 0;
var noMatchCount = 0;
var obj = new TestClass();
obj.IfType<TestClass>(
_ => { matchCount++; },
_ => { noMatchCount++; }
);
Assert.That(matchCount, Is.EqualTo(1));
Assert.That(noMatchCount, Is.EqualTo(0));
}
[Test]
public void IfType_WithResult_Should_Return_Value_When_Type_Matches()
{
var obj = new TestClass { Name = "Test" };
var result = obj.IfType<TestClass, string>(x => x.Name);
Assert.That(result, Is.EqualTo("Test"));
}
[Test]
public void IfType_WithResult_Should_Return_Default_When_Type_Does_Not_Match()
{
var obj = new TestClass();
var result = obj.IfType<string, string>(x => x);
Assert.That(result, Is.Null);
}
[Test]
public void As_Should_Return_Instance_When_Type_Matches()
{
var obj = new TestClass();
var result = obj.As<TestClass>();
Assert.That(result, Is.Not.Null);
Assert.That(result, Is.SameAs(obj));
}
[Test]
public void As_Should_Return_Null_When_Type_Does_Not_Match()
{
var obj = new TestClass();
var result = obj.As<string>();
Assert.That(result, Is.Null);
}
[Test]
public void Do_Should_Execute_Action_And_Return_Object()
{
var obj = new TestClass { Value = 5 };
var result = obj.Do(x => x.Value = 10);
Assert.That(result, Is.SameAs(obj));
Assert.That(obj.Value, Is.EqualTo(10));
}
[Test]
public void Do_Should_Support_Chaining()
{
var obj = new TestClass { Value = 1, Name = "A" };
obj.Do(x => x.Value = 2)
.Do(x => x.Name = "B");
Assert.That(obj.Value, Is.EqualTo(2));
Assert.That(obj.Name, Is.EqualTo("B"));
}
[Test]
public void SwitchType_Should_Execute_Matching_Handler()
{
var obj = new TestClass();
var executed = false;
obj.SwitchType(
(typeof(TestClass), _ => { executed = true; }),
(typeof(string), _ => { Assert.Fail("Should not execute"); })
);
Assert.That(executed, Is.True);
}
[Test]
public void SwitchType_Should_Execute_First_Matching_Handler()
{
var obj = new TestClass();
var count = 0;
obj.SwitchType(
(typeof(TestClass), _ => { count++; }),
(typeof(TestClass), _ => { count++; })
);
Assert.That(count, Is.EqualTo(1));
}
[Test]
public void SwitchType_Should_Not_Execute_When_No_Match()
{
var obj = new TestClass();
var executed = false;
obj.SwitchType(
(typeof(string), _ => { executed = true; }),
(typeof(int), _ => { executed = true; })
);
Assert.That(executed, Is.False);
}
}
public class TestClass
{
public int Value { get; set; }
public string Name { get; set; } = string.Empty;
}

View File

@ -0,0 +1,262 @@
using System.Reflection;
using GFramework.Core.ioc;
using GFramework.Core.logging;
using GFramework.Core.Tests.system;
using NUnit.Framework;
namespace GFramework.Core.Tests.ioc;
[TestFixture]
public class IocContainerTests
{
[SetUp]
public void SetUp()
{
// 初始化 LoggerFactoryResolver 以支持 IocContainer
LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider();
_container = new IocContainer();
// 直接初始化 logger 字段
var loggerField = typeof(IocContainer).GetField("_logger",
BindingFlags.NonPublic | BindingFlags.Instance);
loggerField?.SetValue(_container,
LoggerFactoryResolver.Provider.CreateLogger(nameof(IocContainer)));
}
private IocContainer _container = null!;
private readonly Dictionary<Type, object> _mockContextServices = new();
[Test]
public void RegisterSingleton_Should_Register_Instance()
{
var instance = new TestService();
Assert.DoesNotThrow(() => _container.RegisterSingleton(instance));
}
[Test]
public void RegisterSingleton_WithDuplicate_Should_ThrowInvalidOperationException()
{
var instance1 = new TestService();
var instance2 = new TestService();
_container.RegisterSingleton(instance1);
Assert.Throws<InvalidOperationException>(() => _container.RegisterSingleton(instance2));
}
[Test]
public void RegisterSingleton_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.RegisterSingleton(instance));
}
[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);
}
[Test]
public void RegisterPlurality_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.RegisterPlurality(instance));
}
[Test]
public void Register_Generic_Should_Register_Instance()
{
var instance = new TestService();
_container.Register(instance);
Assert.That(_container.Contains<TestService>(), Is.True);
}
[Test]
public void Register_Generic_AfterFreeze_Should_ThrowInvalidOperationException()
{
var instance = new TestService();
_container.Freeze();
Assert.Throws<InvalidOperationException>(() => _container.Register(instance));
}
[Test]
public void Register_Type_Should_Register_Instance()
{
var instance = new TestService();
_container.Register(typeof(TestService), instance);
Assert.That(_container.Contains<TestService>(), Is.True);
}
[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));
}
[Test]
public void Get_WithNoInstances_Should_ReturnNull()
{
var result = _container.Get<TestService>();
Assert.That(result, Is.Null);
}
[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));
}
[Test]
public void GetRequired_WithNoInstances_Should_ThrowInvalidOperationException()
{
Assert.Throws<InvalidOperationException>(() => _container.GetRequired<TestService>());
}
[Test]
public void GetRequired_WithMultipleInstances_Should_ThrowInvalidOperationException()
{
_container.Register(new TestService());
_container.Register(new TestService());
Assert.Throws<InvalidOperationException>(() => _container.GetRequired<TestService>());
}
[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));
}
[Test]
public void GetAll_WithNoInstances_Should_Return_Empty_Array()
{
var results = _container.GetAll<TestService>();
Assert.That(results.Count, Is.EqualTo(0));
}
[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));
}
[Test]
public void Contains_WithExistingInstance_Should_ReturnTrue()
{
var instance = new TestService();
_container.Register(instance);
Assert.That(_container.Contains<TestService>(), Is.True);
}
[Test]
public void Contains_WithNoInstances_Should_ReturnFalse()
{
Assert.That(_container.Contains<TestService>(), Is.False);
}
[Test]
public void ContainsInstance_WithExistingInstance_Should_ReturnTrue()
{
var instance = new TestService();
_container.Register(instance);
Assert.That(_container.ContainsInstance(instance), Is.True);
}
[Test]
public void ContainsInstance_WithNonExistingInstance_Should_ReturnFalse()
{
var instance = new TestService();
Assert.That(_container.ContainsInstance(instance), Is.False);
}
[Test]
public void Clear_Should_Remove_All_Instances()
{
var instance = new TestService();
_container.Register(instance);
_container.Clear();
Assert.That(_container.Contains<TestService>(), Is.False);
}
[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));
}
[Test]
public void RegisterSystem_Should_Register_Instance()
{
var system = new TestSystem();
_container.RegisterSystem(system);
Assert.That(_container.Contains<TestSystem>(), Is.True);
}
}
public interface IService;
public sealed class TestService : IService
{
public int Priority { get; set; }
}

View File

@ -1,4 +1,4 @@
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.model;
@ -38,7 +38,7 @@ public sealed class AsyncTestModel : AbstractModel, IAsyncInitializable
/// 处理架构阶段事件
/// </summary>
/// <param name="phase">架构阶段枚举值</param>
public void OnArchitecturePhase(ArchitecturePhase phase)
public override void OnArchitecturePhase(ArchitecturePhase phase)
{
}

View File

@ -1,4 +1,4 @@
using GFramework.Core.Abstractions.enums;
using GFramework.Core.Abstractions.enums;
using GFramework.Core.model;
namespace GFramework.Core.Tests.model;
@ -24,7 +24,7 @@ public sealed class TestModel : AbstractModel, ITestModel
}
public void OnArchitecturePhase(ArchitecturePhase phase)
public override void OnArchitecturePhase(ArchitecturePhase phase)
{
}

View File

@ -0,0 +1,131 @@
using GFramework.Core.Abstractions.pool;
using GFramework.Core.pool;
using NUnit.Framework;
namespace GFramework.Core.Tests.pool;
[TestFixture]
public class ObjectPoolTests
{
[SetUp]
public void SetUp()
{
_pool = new TestObjectPool();
}
private TestObjectPool _pool = null!;
[Test]
public void Acquire_Should_Create_New_Object_When_Pool_Empty()
{
var obj = _pool.Acquire("test");
Assert.That(obj, Is.Not.Null);
Assert.That(obj.PoolKey, Is.EqualTo("test"));
Assert.That(obj.OnAcquireCalled, Is.True);
}
[Test]
public void Acquire_Should_Return_Pooled_Object()
{
var obj1 = _pool.Acquire("test");
obj1.TestValue = 100;
_pool.Release("test", obj1);
var obj2 = _pool.Acquire("test");
Assert.That(obj2, Is.SameAs(obj1));
Assert.That(obj2.TestValue, Is.EqualTo(100));
Assert.That(obj2.OnAcquireCalled, Is.True);
}
[Test]
public void Release_Should_Call_OnRelease()
{
var obj = _pool.Acquire("test");
_pool.Release("test", obj);
Assert.That(obj.OnReleaseCalled, Is.True);
}
[Test]
public void Clear_Should_Destroy_All_Objects()
{
var obj1 = _pool.Acquire("key1");
var obj2 = _pool.Acquire("key2");
_pool.Release("key1", obj1);
_pool.Release("key2", obj2);
_pool.Clear();
Assert.That(obj1.OnPoolDestroyCalled, Is.True);
Assert.That(obj2.OnPoolDestroyCalled, Is.True);
}
[Test]
public void Multiple_Pools_Should_Be_Independent()
{
var obj1 = _pool.Acquire("key1");
var obj2 = _pool.Acquire("key2");
_pool.Release("key1", obj1);
var obj3 = _pool.Acquire("key1");
var obj4 = _pool.Acquire("key2");
Assert.That(obj3, Is.SameAs(obj1));
Assert.That(obj4, Is.Not.SameAs(obj2));
}
[Test]
public void OnAcquire_Should_Be_Called_On_New_And_Pooled_Objects()
{
var obj1 = _pool.Acquire("test");
Assert.That(obj1.OnAcquireCalled, Is.True);
_pool.Release("test", obj1);
obj1.OnAcquireCalled = false;
var obj2 = _pool.Acquire("test");
Assert.That(obj2.OnAcquireCalled, Is.True);
}
}
public class TestObjectPool : AbstractObjectPoolSystem<string, TestPoolableObject>
{
protected override TestPoolableObject Create(string key)
{
return new TestPoolableObject { PoolKey = key };
}
protected override void OnInit()
{
}
}
public class TestPoolableObject : IPoolableObject
{
public string PoolKey { get; set; } = string.Empty;
public int TestValue { get; set; }
public bool OnAcquireCalled { get; set; }
public bool OnReleaseCalled { get; set; }
public bool OnPoolDestroyCalled { get; set; }
public void OnAcquire()
{
OnAcquireCalled = true;
}
public void OnRelease()
{
OnReleaseCalled = true;
}
public void OnPoolDestroy()
{
OnPoolDestroyCalled = true;
}
}

View File

@ -0,0 +1,133 @@
using GFramework.Core.property;
using NUnit.Framework;
namespace GFramework.Core.Tests.property;
[TestFixture]
public class BindablePropertyTests
{
[Test]
public void Value_Get_Should_Return_Default_Value()
{
var property = new BindableProperty<int>(5);
Assert.That(property.Value, Is.EqualTo(5));
}
[Test]
public void Value_Set_Should_Trigger_Event()
{
var property = new BindableProperty<int>();
var receivedValue = 0;
property.Register(value => { receivedValue = value; });
property.Value = 42;
Assert.That(receivedValue, Is.EqualTo(42));
}
[Test]
public void Value_Set_To_Same_Value_Should_Not_Trigger_Event()
{
var property = new BindableProperty<int>(5);
var count = 0;
property.Register(_ => { count++; });
property.Value = 5;
Assert.That(count, Is.EqualTo(0));
}
[Test]
public void UnRegister_Should_Remove_Handler()
{
var property = new BindableProperty<int>();
var count = 0;
Action<int> handler = _ => { count++; };
property.Register(handler);
property.Value = 1;
Assert.That(count, Is.EqualTo(1));
property.UnRegister(handler);
property.Value = 2;
Assert.That(count, Is.EqualTo(1));
}
[Test]
public void RegisterWithInitValue_Should_Call_Handler_Immediately()
{
var property = new BindableProperty<int>(5);
var receivedValue = 0;
property.RegisterWithInitValue(value => { receivedValue = value; });
Assert.That(receivedValue, Is.EqualTo(5));
}
[Test]
public void SetValueWithoutEvent_Should_Not_Trigger_Event()
{
var property = new BindableProperty<int>();
var count = 0;
property.Register(_ => { count++; });
property.SetValueWithoutEvent(42);
Assert.That(count, Is.EqualTo(0));
Assert.That(property.Value, Is.EqualTo(42));
}
[Test]
public void WithComparer_Should_Use_Custom_Comparer()
{
var property = new BindableProperty<string>("test").WithComparer((a, b) => a.Length == b.Length);
var count = 0;
property.Register(_ => { count++; });
property.Value = "hello";
// "test" 和 "hello" 长度都是 4所以不应该触发事件
Assert.That(count, Is.EqualTo(0));
}
[Test]
public void Multiple_Handlers_Should_All_Be_Called()
{
var property = new BindableProperty<int>();
var count1 = 0;
var count2 = 0;
property.Register(_ => { count1++; });
property.Register(_ => { count2++; });
property.Value = 42;
Assert.That(count1, Is.EqualTo(1));
Assert.That(count2, Is.EqualTo(1));
}
[Test]
public void Register_Should_Return_IUnRegister()
{
var property = new BindableProperty<int>();
var unRegister = property.Register(_ => { });
Assert.That(unRegister, Is.Not.Null);
}
[Test]
public void ToString_Should_Return_Value_As_String()
{
var property = new BindableProperty<int>(42);
var result = property.ToString();
Assert.That(result, Is.EqualTo("42"));
}
}

View File

@ -0,0 +1,74 @@
using GFramework.Core.Abstractions.query;
using GFramework.Core.query;
using NUnit.Framework;
namespace GFramework.Core.Tests.query;
[TestFixture]
public class QueryBusTests
{
[SetUp]
public void SetUp()
{
_queryBus = new QueryBus();
}
private QueryBus _queryBus = null!;
[Test]
public void Send_Should_Return_Query_Result()
{
var input = new TestQueryInput { Value = 10 };
var query = new TestQuery(input);
var result = _queryBus.Send(query);
Assert.That(result, Is.EqualTo(20));
}
[Test]
public void Send_WithNullQuery_Should_ThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => _queryBus.Send<int>(null!));
}
[Test]
public void Send_WithStringResult_Should_Return_String()
{
var input = new TestQueryInput { Value = 5 };
var query = new TestStringQuery(input);
var result = _queryBus.Send(query);
Assert.That(result, Is.EqualTo("Result: 10"));
}
}
public sealed class TestQueryInput : IQueryInput
{
public int Value { get; init; }
}
public sealed class TestQuery : AbstractQuery<TestQueryInput, int>
{
public TestQuery(TestQueryInput input) : base(input)
{
}
protected override int OnDo(TestQueryInput input)
{
return input.Value * 2;
}
}
public sealed class TestStringQuery : AbstractQuery<TestQueryInput, string>
{
public TestStringQuery(TestQueryInput input) : base(input)
{
}
protected override string OnDo(TestQueryInput input)
{
return $"Result: {input.Value * 2}";
}
}

View File

@ -1,28 +0,0 @@
using GFramework.Core.Abstractions.query;
using GFramework.Core.extensions;
using GFramework.Core.query;
using GFramework.Core.Tests.model;
namespace GFramework.Core.Tests.query;
/// <summary>
/// 测试查询类,用于执行测试查询操作
/// </summary>
/// <param name="input">测试查询输入参数</param>
public class TestQuery(TestQueryInput input) : AbstractQuery<TestQueryInput, int>(input)
{
/// <summary>
/// 执行查询操作的重写方法
/// </summary>
/// <param name="input">测试查询输入参数</param>
/// <returns>返回固定的整数值42</returns>
protected override int OnDo(TestQueryInput input)
{
return this.GetModel<ITestModel>()!.GetCurrentXp;
}
}
/// <summary>
/// 测试查询输入类,实现查询输入接口
/// </summary>
public sealed class TestQueryInput : IQueryInput;

View File

@ -142,10 +142,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
}
/// <summary>
/// 测试事件是否能够被正确接收和处理
/// 测试事件是否能够被正确接收和处理
/// </summary>
/// <remarks>
/// 该测试验证了事件系统的注册和发送功能,确保事件能够被正确传递给注册的处理器
/// 该测试验证了事件系统的注册和发送功能,确保事件能够被正确传递给注册的处理器
/// </remarks>
[Test]
public void Event_Should_Be_Received()
@ -168,10 +168,10 @@ public class SyncArchitectureTests : ArchitectureTestsBase<SyncTestArchitecture>
}
/// <summary>
/// 测试事件取消注册功能是否正常工作
/// 测试事件取消注册功能是否正常工作
/// </summary>
/// <remarks>
/// 该测试验证了事件处理器的取消注册功能,确保取消注册后事件处理器不再被调用
/// 该测试验证了事件处理器的取消注册功能,确保取消注册后事件处理器不再被调用
/// </remarks>
[Test]
public void Event_UnRegister_Should_Work()

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
</PropertyGroup>