Files
zeling_v2/Assets/Tests/EditMode/EventSystemTests.cs

256 lines
9.2 KiB
C#
Raw Permalink 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 System;
using System.Collections.Generic;
using NUnit.Framework;
using BaseGames.Core.Events;
using BaseGames.Core;
using UObject = UnityEngine.Object;
using UnityEngine;
namespace BaseGames.Tests.EditMode
{
/// <summary>
/// SO 事件系统 + ServiceLocator 单元测试EditMode无需 Play Mode
/// </summary>
[TestFixture]
public class EventSystemTests
{
// ── EventSubscription ────────────────────────────────────────────────
[Test]
public void EventSubscription_Dispose_CallsUnsubscribeAction()
{
bool called = false;
var sub = new EventSubscription(() => called = true);
sub.Dispose();
Assert.IsTrue(called, "Dispose 应调用 unsubscribe action");
}
[Test]
public void EventSubscription_Dispose_NullAction_DoesNotThrow()
{
var sub = new EventSubscription(null);
Assert.DoesNotThrow(() => sub.Dispose());
}
// ── CompositeDisposable ──────────────────────────────────────────────
[Test]
public void CompositeDisposable_Clear_DisposesAllItems()
{
var composite = new CompositeDisposable();
int count = 0;
composite.Add(new EventSubscription(() => count++));
composite.Add(new EventSubscription(() => count++));
composite.Add(new EventSubscription(() => count++));
composite.Clear();
Assert.AreEqual(3, count, "Clear 应 Dispose 所有已添加的订阅");
}
[Test]
public void CompositeDisposable_Clear_TwiceSafe()
{
var composite = new CompositeDisposable();
int count = 0;
composite.Add(new EventSubscription(() => count++));
composite.Clear();
composite.Clear(); // 第二次 Clear 不应重复 Dispose
Assert.AreEqual(1, count, "Clear 两次不应重复 Dispose");
}
[Test]
public void CompositeDisposable_Dispose_SameAsClear()
{
var composite = new CompositeDisposable();
bool disposed = false;
composite.Add(new EventSubscription(() => disposed = true));
((IDisposable)composite).Dispose();
Assert.IsTrue(disposed);
}
[Test]
public void AddTo_ReturnsOriginalSubscription()
{
var composite = new CompositeDisposable();
bool called = false;
var sub = new EventSubscription(() => called = true);
var returned = sub.AddTo(composite);
returned.Dispose();
Assert.IsTrue(called, "AddTo 返回的订阅 Dispose 后应触发原 unsubscribe");
}
[Test]
public void AddTo_Collection_AddsToList()
{
var list = new List<IDisposable>();
bool called = false;
var sub = new EventSubscription(() => called = true);
sub.AddTo(list);
Assert.AreEqual(1, list.Count, "AddTo(ICollection) 应将订阅添加到列表");
list[0].Dispose();
Assert.IsTrue(called);
}
// ── IntEventChannelSO ────────────────────────────────────────────────
[Test]
public void IntEventChannel_Raise_CallsAllSubscribers()
{
var channel = ScriptableObject.CreateInstance<IntEventChannelSO>();
try
{
int sum = 0;
channel.OnEventRaised += v => sum += v;
channel.OnEventRaised += v => sum += v;
channel.Raise(5);
Assert.AreEqual(10, sum, "两个订阅者应各收到一次事件");
}
finally
{
UObject.DestroyImmediate(channel);
}
}
[Test]
public void IntEventChannel_Raise_NoSubscribers_DoesNotThrow()
{
var channel = ScriptableObject.CreateInstance<IntEventChannelSO>();
try
{
Assert.DoesNotThrow(() => channel.Raise(42));
}
finally
{
UObject.DestroyImmediate(channel);
}
}
[Test]
public void IntEventChannel_UnsubscribeAfterDispose()
{
var channel = ScriptableObject.CreateInstance<IntEventChannelSO>();
try
{
int callCount = 0;
void Handler(int v) => callCount++;
channel.OnEventRaised += Handler;
channel.Raise(1);
Assert.AreEqual(1, callCount);
channel.OnEventRaised -= Handler;
channel.Raise(1);
Assert.AreEqual(1, callCount, "取消订阅后不应再收到事件");
}
finally
{
UObject.DestroyImmediate(channel);
}
}
// ── VoidEventChannelSO ───────────────────────────────────────────────
[Test]
public void VoidEventChannel_Raise_CallsSubscriber()
{
var channel = ScriptableObject.CreateInstance<VoidEventChannelSO>();
try
{
bool received = false;
channel.OnEventRaised += () => received = true;
channel.Raise();
Assert.IsTrue(received);
}
finally
{
UObject.DestroyImmediate(channel);
}
}
// ── ServiceLocator ───────────────────────────────────────────────────
[SetUp]
public void SetUp() => ServiceLocator.Reset();
[TearDown]
public void TearDown() => ServiceLocator.Reset();
[Test]
public void ServiceLocator_RegisterAndGet_ReturnsInstance()
{
var mock = new MockService();
ServiceLocator.Register<IMockService>(mock);
var retrieved = ServiceLocator.Get<IMockService>();
Assert.AreSame(mock, retrieved);
}
[Test]
public void ServiceLocator_GetUnregistered_ThrowsInvalidOperation()
{
Assert.Throws<InvalidOperationException>(
() => ServiceLocator.Get<IMockService>());
}
[Test]
public void ServiceLocator_GetOrDefault_Unregistered_ReturnsDefault()
{
var result = ServiceLocator.GetOrDefault<IMockService>();
Assert.IsNull(result);
}
[Test]
public void ServiceLocator_GetOrDefault_Registered_ReturnsInstance()
{
var mock = new MockService();
ServiceLocator.Register<IMockService>(mock);
var result = ServiceLocator.GetOrDefault<IMockService>();
Assert.AreSame(mock, result);
}
[Test]
public void ServiceLocator_RegisterIfAbsent_DoesNotOverwrite()
{
var first = new MockService();
var second = new MockService();
ServiceLocator.Register<IMockService>(first);
ServiceLocator.RegisterIfAbsent<IMockService>(second);
Assert.AreSame(first, ServiceLocator.Get<IMockService>(),
"RegisterIfAbsent 不应覆盖已存在的注册");
}
[Test]
public void ServiceLocator_Unregister_RemovesService()
{
ServiceLocator.Register<IMockService>(new MockService());
ServiceLocator.Unregister<IMockService>();
Assert.Throws<InvalidOperationException>(
() => ServiceLocator.Get<IMockService>());
}
[Test]
public void ServiceLocator_Unregister_WithWrongInstance_DoesNotRemove()
{
var first = new MockService();
var second = new MockService();
ServiceLocator.Register<IMockService>(first);
ServiceLocator.Unregister<IMockService>(second); // 不同实例,不应移除
Assert.AreSame(first, ServiceLocator.Get<IMockService>(),
"错误实例的 Unregister 不应移除已注册的服务");
}
[Test]
public void ServiceLocator_OverrideForTest_ReplacesService()
{
var original = new MockService { Value = 1 };
var replacement = new MockService { Value = 99 };
ServiceLocator.Register<IMockService>(original);
ServiceLocator.OverrideForTest<IMockService>(replacement);
Assert.AreEqual(99, ServiceLocator.Get<IMockService>().Value);
}
// ── Test Helpers ─────────────────────────────────────────────────────
private interface IMockService { int Value { get; set; } }
private class MockService : IMockService { public int Value { get; set; } }
}
}