Add unit tests for security contour, COM port shutdown and VFX service
- Äîáàâëåíû EditMode òåñòû äëÿ âåðèôèêàöèè ââîäà PIN-êîäà àâòîðèçàöèè ïåðåä îòêðûòèåì ìåíþ íàñòðîåê â MainMenuControllerServiceActionTests.cs. - Ñîçäàíû íîâûå EditMode òåñòû VfxServiceTests.cs, ïîêðûâàþùèå null-safety è êîððåêòíîå ñîçäàíèå GameObject ñèñòåì ÷àñòèö äëÿ IVfxService è GameVfxService. - Ñîçäàí íîâûé EditMode êëàññ òåñòîâ ComSystemShutdownTests.cs, ïðîâåðÿþùèé áûñòðîå è áåçîïàñíîå çàêðûòèå COM-ñèñòåìû. - Èñïðàâëåí ïîðÿäîê âûçîâà RequestClose() â ServiceTextInputModalWindow.Confirm() äëÿ ïðåäîòâðàùåíèÿ çàêðûòèÿ ìîäàëüíûõ îêîí ïîâåðõ òåêóùåãî ïðè çàêðûòèè îêíà ââîäà. - Èñïðàâëåíî óíè÷òîæåíèå îáúåêòîâ â GameVfxService.cs è JumpPlayerController.cs â EditMode ñ ïîìîùüþ ïðîâåðêè Application.isPlaying. - Äîáàâëåíà ëåíèâàÿ èíèöèàëèçàöèÿ Rigidbody2D â ìåòîäàõ Bounce() è Die() â JumpPlayerController.cs äëÿ ïðåäîòâðàùåíèÿ NullReferenceException â èçîëèðîâàííûõ òåñòàõ. - Âñå 174 EditMode è 7 PlayMode òåñòîâ óñïåøíî ïðîéäåíû â Unity Editor.
This commit is contained in:
parent
e70120f0b0
commit
9549d42ea3
@ -403,7 +403,16 @@ namespace DanroJump.Gameplay
|
||||
/// </summary>
|
||||
public void Bounce(float velocity)
|
||||
{
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, Mathf.Max(body.linearVelocity.y, velocity));
|
||||
if (body == null)
|
||||
{
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
}
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
body.linearVelocity = new Vector2(body.linearVelocity.x, Mathf.Max(body.linearVelocity.y, velocity));
|
||||
}
|
||||
|
||||
jumpAnimationPulseUntil = Time.time + jumpAnimationPulseDuration;
|
||||
audioService?.Play(GameAudioEvent.PlayerJump, transform.position);
|
||||
vfxService?.SpawnJumpEffect(transform.position);
|
||||
@ -1366,7 +1375,17 @@ namespace DanroJump.Gameplay
|
||||
IsDead = true;
|
||||
respawnBlocked = false;
|
||||
respawnAtTime = -1f;
|
||||
body.linearVelocity = Vector2.zero;
|
||||
|
||||
if (body == null)
|
||||
{
|
||||
body = GetComponent<Rigidbody2D>();
|
||||
}
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
body.linearVelocity = Vector2.zero;
|
||||
}
|
||||
|
||||
ResetMoveSpeedMultiplier();
|
||||
ResetHeightLift();
|
||||
EndEnemyPassThrough();
|
||||
@ -1555,7 +1574,14 @@ namespace DanroJump.Gameplay
|
||||
var clone = wrapRendererClones[index];
|
||||
if (clone != null)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(clone.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1716,7 +1742,14 @@ namespace DanroJump.Gameplay
|
||||
var clone = wrapRendererClones[index];
|
||||
if (clone != null)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(clone.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
wrapRendererClones.RemoveAt(index);
|
||||
@ -1750,7 +1783,14 @@ namespace DanroJump.Gameplay
|
||||
var clone = wrapRendererClones[index];
|
||||
if (clone != null)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Destroy(clone.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyImmediate(clone.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
wrapRendererClones.RemoveAt(index);
|
||||
|
||||
@ -256,9 +256,8 @@ namespace DanroJump.UI.MainMenu
|
||||
|
||||
var confirmedCallback = confirmed;
|
||||
confirmed = null;
|
||||
confirmedCallback.Invoke(state.Value);
|
||||
SetStatus("Значение сохранено.");
|
||||
RequestClose();
|
||||
confirmedCallback.Invoke(state.Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,10 @@ namespace DanroJump.Vfx
|
||||
colorOverLifetime.color = gradient;
|
||||
|
||||
ps.Play();
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnCoinCollectedEffect(Vector3 position)
|
||||
@ -79,7 +82,10 @@ namespace DanroJump.Vfx
|
||||
colorOverLifetime.color = gradient;
|
||||
|
||||
ps.Play();
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnPlayerDeathEffect(Vector3 position)
|
||||
@ -115,7 +121,10 @@ namespace DanroJump.Vfx
|
||||
colorOverLifetime.color = gradient;
|
||||
|
||||
ps.Play();
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnPrizeEffect(Vector3 position)
|
||||
@ -154,7 +163,10 @@ namespace DanroJump.Vfx
|
||||
);
|
||||
|
||||
ps.Play();
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnComErrorEffect(Vector3 position)
|
||||
@ -191,7 +203,10 @@ namespace DanroJump.Vfx
|
||||
colorOverLifetime.color = gradient;
|
||||
|
||||
ps.Play();
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Object.Destroy(go, main.duration + main.startLifetime.constantMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
166
Assets/Tests/EditMode/Editor/ComSystemShutdownTests.cs
Normal file
166
Assets/Tests/EditMode/Editor/ComSystemShutdownTests.cs
Normal file
@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using DanroJump.Hardware.Com;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanroJump.Tests.EditMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Тесты для проверки быстрого и безопасного закрытия (graceful shutdown) COM-системы.
|
||||
/// </summary>
|
||||
public sealed class ComSystemShutdownTests
|
||||
{
|
||||
private GameObject systemGo;
|
||||
private ComSystem comSystem;
|
||||
private MockComTransport mockTransport;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
systemGo = new GameObject("Test_ComSystem");
|
||||
comSystem = systemGo.AddComponent<ComSystem>();
|
||||
|
||||
// Отключаем автоматический запуск и сохранение между сценами
|
||||
SetPrivateField(comSystem, "startOnEnable", false);
|
||||
SetPrivateField(comSystem, "dontDestroyOnLoad", false);
|
||||
SetPrivateField(comSystem, "useEncryptedHandshake", false);
|
||||
SetPrivateField(comSystem, "keepAlive", false);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (comSystem != null)
|
||||
{
|
||||
comSystem.StopSystem(false);
|
||||
}
|
||||
|
||||
if (systemGo != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(systemGo);
|
||||
}
|
||||
|
||||
mockTransport?.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ComSystem_StopSystem_CompletesImmediately()
|
||||
{
|
||||
// Настраиваем mock-окружение
|
||||
var mockProvider = new MockComPortProvider();
|
||||
mockTransport = new MockComTransport();
|
||||
var mockFactory = new MockComTransportFactory(mockTransport);
|
||||
|
||||
comSystem.ConfigureInfrastructure(mockProvider, mockFactory);
|
||||
|
||||
// Запускаем систему
|
||||
comSystem.StartSystem();
|
||||
Assert.That(comSystem.IsRunning, Is.True);
|
||||
|
||||
// Проверяем время остановки
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
comSystem.StopSystem(sendShutdownCommands: false);
|
||||
stopwatch.Stop();
|
||||
|
||||
Assert.That(comSystem.IsRunning, Is.False);
|
||||
Assert.That(stopwatch.ElapsedMilliseconds, Is.LessThan(500), "StopSystem took too long to complete!");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ComSystem_StopSystem_WithShutdownCommands_CompletesImmediately()
|
||||
{
|
||||
var mockProvider = new MockComPortProvider();
|
||||
mockTransport = new MockComTransport();
|
||||
var mockFactory = new MockComTransportFactory(mockTransport);
|
||||
|
||||
comSystem.ConfigureInfrastructure(mockProvider, mockFactory);
|
||||
|
||||
comSystem.StartSystem();
|
||||
Assert.That(comSystem.IsRunning, Is.True);
|
||||
|
||||
// Проверяем время остановки с отправкой команд выключения
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
comSystem.StopSystem(sendShutdownCommands: true);
|
||||
stopwatch.Stop();
|
||||
|
||||
Assert.That(comSystem.IsRunning, Is.False);
|
||||
Assert.That(stopwatch.ElapsedMilliseconds, Is.LessThan(500), "StopSystem with shutdown commands took too long to complete!");
|
||||
}
|
||||
|
||||
private static void SetPrivateField(object target, string fieldName, object value)
|
||||
{
|
||||
var field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null)
|
||||
{
|
||||
throw new ArgumentException($"Field '{fieldName}' not found in type '{target.GetType().FullName}'");
|
||||
}
|
||||
field.SetValue(target, value);
|
||||
}
|
||||
|
||||
private sealed class MockComPortProvider : IComPortProvider
|
||||
{
|
||||
public string[] GetPortNames() => new[] { "COM_TEST" };
|
||||
}
|
||||
|
||||
private sealed class MockComTransportFactory : IComTransportFactory
|
||||
{
|
||||
private readonly IComTransport transport;
|
||||
|
||||
public MockComTransportFactory(IComTransport transport)
|
||||
{
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
public IComTransport Create(SerialSettings settings) => transport;
|
||||
}
|
||||
|
||||
private sealed class MockComTransport : IComTransport
|
||||
{
|
||||
private readonly AutoResetEvent readEvent = new(false);
|
||||
private readonly ConcurrentQueue<string> readQueue = new();
|
||||
private bool isOpen;
|
||||
|
||||
public bool IsOpen => isOpen;
|
||||
|
||||
public void Open()
|
||||
{
|
||||
isOpen = true;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
isOpen = false;
|
||||
readEvent.Set();
|
||||
}
|
||||
|
||||
public void DiscardInBuffer() { }
|
||||
public void DiscardOutBuffer() { }
|
||||
|
||||
public string ReadLine()
|
||||
{
|
||||
while (isOpen)
|
||||
{
|
||||
if (readQueue.TryDequeue(out var line))
|
||||
{
|
||||
return line;
|
||||
}
|
||||
readEvent.WaitOne(10);
|
||||
}
|
||||
throw new System.IO.IOException("Port is closed");
|
||||
}
|
||||
|
||||
public void WriteLine(string value)
|
||||
{
|
||||
// Для простоты теста просто игнорируем команды записи
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a64abf3bf7d4d8849b8bca91eddc37bc
|
||||
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using DanroJump.Prizes.Qr;
|
||||
using DanroJump.Settings;
|
||||
using DanroJump.UI.ArcadeInput;
|
||||
using DanroJump.UI.MainMenu;
|
||||
using DanroJump.UI.Modals;
|
||||
using NUnit.Framework;
|
||||
@ -81,6 +82,90 @@ namespace DanroJump.Tests.EditMode
|
||||
textInputModal.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OpenSettings_RequiresPinCodeInput()
|
||||
{
|
||||
var controller = CreateController();
|
||||
var settings = new StubSettingsService();
|
||||
var settingsModal = new SettingsModalWindow(new VisualElement(), settings, null);
|
||||
var textInputRoot = CreateTextInputRoot();
|
||||
var textInputModal = new ServiceTextInputModalWindow(textInputRoot);
|
||||
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceSettingsService", settings);
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceTextInputModal", textInputModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "settingsModal", settingsModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "modalStack", new ModalStackController(new VisualElement(), null));
|
||||
|
||||
InvokeOpenSettings(controller);
|
||||
|
||||
Assert.That(textInputModal.IsOpen, Is.True);
|
||||
Assert.That(settingsModal.IsOpen, Is.False);
|
||||
Assert.That(textInputRoot.Q<Label>("ServiceTextInputTitle").text, Is.EqualTo("Авторизация"));
|
||||
Assert.That(textInputRoot.Q<Label>("ServiceTextInputSetting").text, Is.EqualTo("Введите PIN-код для доступа к настройкам"));
|
||||
|
||||
settingsModal.Dispose();
|
||||
textInputModal.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OpenSettings_WithCorrectPIN_OpensSettingsModal()
|
||||
{
|
||||
var controller = CreateController();
|
||||
var settings = new StubSettingsService();
|
||||
var settingsModal = new SettingsModalWindow(new VisualElement(), settings, null);
|
||||
var textInputRoot = CreateTextInputRoot();
|
||||
var textInputModal = new ServiceTextInputModalWindow(textInputRoot);
|
||||
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceSettingsService", settings);
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceTextInputModal", textInputModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "settingsModal", settingsModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "modalStack", new ModalStackController(new VisualElement(), null));
|
||||
|
||||
InvokeOpenSettings(controller);
|
||||
|
||||
var profile = new ArcadeStringInputProfile("0123456789", 4);
|
||||
var correctState = new ArcadeStringInputState(profile, "1234");
|
||||
TestObjectFactory.SetPrivateField(textInputModal, "state", correctState);
|
||||
|
||||
Assert.That(textInputModal.Confirm(), Is.True);
|
||||
|
||||
Assert.That(settingsModal.IsOpen, Is.True);
|
||||
|
||||
settingsModal.Dispose();
|
||||
textInputModal.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OpenSettings_WithIncorrectPIN_DoesNotOpenSettingsModalAndPlaysError()
|
||||
{
|
||||
var controller = CreateController();
|
||||
var settings = new StubSettingsService();
|
||||
var settingsModal = new SettingsModalWindow(new VisualElement(), settings, null);
|
||||
var textInputRoot = CreateTextInputRoot();
|
||||
var textInputModal = new ServiceTextInputModalWindow(textInputRoot);
|
||||
var stubAudio = new StubAudioService();
|
||||
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceSettingsService", settings);
|
||||
TestObjectFactory.SetPrivateField(controller, "serviceTextInputModal", textInputModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "settingsModal", settingsModal);
|
||||
TestObjectFactory.SetPrivateField(controller, "audioService", stubAudio);
|
||||
TestObjectFactory.SetPrivateField(controller, "modalStack", new ModalStackController(new VisualElement(), null));
|
||||
|
||||
InvokeOpenSettings(controller);
|
||||
|
||||
var profile = new ArcadeStringInputProfile("0123456789", 4);
|
||||
var incorrectState = new ArcadeStringInputState(profile, "9999");
|
||||
TestObjectFactory.SetPrivateField(textInputModal, "state", incorrectState);
|
||||
|
||||
Assert.That(textInputModal.Confirm(), Is.True);
|
||||
|
||||
Assert.That(settingsModal.IsOpen, Is.False);
|
||||
Assert.That(stubAudio.LastPlayEvent, Is.EqualTo(DanroJump.Audio.GameAudioEvent.UiError));
|
||||
|
||||
settingsModal.Dispose();
|
||||
textInputModal.Dispose();
|
||||
}
|
||||
|
||||
private MainMenuController CreateController()
|
||||
{
|
||||
gameObject = new GameObject("MainMenuControllerServiceActionTest");
|
||||
@ -110,6 +195,15 @@ namespace DanroJump.Tests.EditMode
|
||||
method.Invoke(controller, new object[] { tier, settingKey });
|
||||
}
|
||||
|
||||
private static void InvokeOpenSettings(MainMenuController controller)
|
||||
{
|
||||
var method = typeof(MainMenuController).GetMethod(
|
||||
"OpenSettings",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Assert.That(method, Is.Not.Null);
|
||||
method.Invoke(controller, null);
|
||||
}
|
||||
|
||||
private static VisualElement CreateQrSettingsRoot()
|
||||
{
|
||||
var root = new VisualElement { name = "QrSettingsModal" };
|
||||
@ -138,6 +232,21 @@ namespace DanroJump.Tests.EditMode
|
||||
return root;
|
||||
}
|
||||
|
||||
private sealed class StubAudioService : DanroJump.Audio.IGameAudioService
|
||||
{
|
||||
public bool IsReady => true;
|
||||
public bool IsMusicPlaying => false;
|
||||
public DanroJump.Audio.GameMusicCue? CurrentMusicCue => null;
|
||||
public DanroJump.Audio.GameAudioEvent? LastPlayEvent { get; private set; }
|
||||
|
||||
public void Play(DanroJump.Audio.GameAudioEvent eventId) => LastPlayEvent = eventId;
|
||||
public void Play(DanroJump.Audio.GameAudioEvent eventId, Vector3 worldPosition) => LastPlayEvent = eventId;
|
||||
public void StartMusic() { }
|
||||
public void PlayMusic(DanroJump.Audio.GameMusicCue cue) { }
|
||||
public void StopMusic() { }
|
||||
public void ApplyServiceVolumes() { }
|
||||
}
|
||||
|
||||
private sealed class StubSettingsService : IServiceSettingsService
|
||||
{
|
||||
private readonly Dictionary<string, ServiceSettingDefinition> definitions = new();
|
||||
|
||||
120
Assets/Tests/EditMode/Editor/VfxServiceTests.cs
Normal file
120
Assets/Tests/EditMode/Editor/VfxServiceTests.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
using DanroJump.Gameplay;
|
||||
using DanroJump.Vfx;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanroJump.Tests.EditMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Тесты для службы визуальных эффектов IVfxService и GameVfxService.
|
||||
/// </summary>
|
||||
public sealed class VfxServiceTests
|
||||
{
|
||||
private readonly List<GameObject> createdObjects = new();
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
foreach (var obj in createdObjects)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
}
|
||||
createdObjects.Clear();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VfxService_NullSafety_PlayerAndCollectibleDoNotThrowWhenVfxServiceIsNull()
|
||||
{
|
||||
// Тест Null-safety для игрока
|
||||
var playerObj = new GameObject("TestPlayer");
|
||||
createdObjects.Add(playerObj);
|
||||
var body = playerObj.AddComponent<Rigidbody2D>();
|
||||
body.gravityScale = 0f;
|
||||
playerObj.AddComponent<BoxCollider2D>();
|
||||
|
||||
var playerVisual = new GameObject("Body");
|
||||
playerVisual.transform.SetParent(playerObj.transform);
|
||||
playerVisual.AddComponent<SpriteRenderer>();
|
||||
|
||||
var groundCheck = new GameObject("GroundCheck");
|
||||
groundCheck.transform.SetParent(playerObj.transform);
|
||||
groundCheck.transform.localPosition = new Vector3(0f, -0.5f, 0f);
|
||||
|
||||
var player = playerObj.AddComponent<JumpPlayerController>();
|
||||
|
||||
var camObj = new GameObject("TestCam");
|
||||
createdObjects.Add(camObj);
|
||||
var camera = camObj.AddComponent<Camera>();
|
||||
|
||||
// Внедряем null в качестве IVfxService
|
||||
player.Construct(camera, null, null);
|
||||
|
||||
// Проверяем, что вызовы Bounce и Die не выбрасывают NullReferenceException
|
||||
Assert.DoesNotThrow(() => player.Bounce(10f));
|
||||
Assert.DoesNotThrow(() => player.Kill());
|
||||
|
||||
// Тест Null-safety для CoinCollectible
|
||||
var coinObj = new GameObject("TestCoin");
|
||||
createdObjects.Add(coinObj);
|
||||
coinObj.AddComponent<BoxCollider2D>();
|
||||
var coin = coinObj.AddComponent<CoinCollectible>();
|
||||
coin.Construct(null, null, null);
|
||||
|
||||
// Имитируем сбор монеты
|
||||
var method = typeof(CoinCollectible).GetMethod("OnCollected", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
Assert.That(method, Is.Not.Null);
|
||||
Assert.DoesNotThrow(() => method.Invoke(coin, new object[] { player }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GameVfxService_SpawnMethods_CreateParticleSystemGameObjects()
|
||||
{
|
||||
var vfxService = new GameVfxService();
|
||||
var spawnPosition = new Vector3(1f, 2f, 3f);
|
||||
|
||||
// 1. Тест SpawnJumpEffect
|
||||
vfxService.SpawnJumpEffect(spawnPosition);
|
||||
var jumpVfx = GameObject.Find("VFX_Jump");
|
||||
Assert.That(jumpVfx, Is.Not.Null);
|
||||
createdObjects.Add(jumpVfx);
|
||||
Assert.That(jumpVfx.transform.position, Is.EqualTo(spawnPosition));
|
||||
Assert.That(jumpVfx.GetComponent<ParticleSystem>(), Is.Not.Null);
|
||||
|
||||
// 2. Тест SpawnCoinCollectedEffect
|
||||
vfxService.SpawnCoinCollectedEffect(spawnPosition);
|
||||
var coinVfx = GameObject.Find("VFX_CoinCollected");
|
||||
Assert.That(coinVfx, Is.Not.Null);
|
||||
createdObjects.Add(coinVfx);
|
||||
Assert.That(coinVfx.transform.position, Is.EqualTo(spawnPosition));
|
||||
Assert.That(coinVfx.GetComponent<ParticleSystem>(), Is.Not.Null);
|
||||
|
||||
// 3. Тест SpawnPlayerDeathEffect
|
||||
vfxService.SpawnPlayerDeathEffect(spawnPosition);
|
||||
var deathVfx = GameObject.Find("VFX_PlayerDeath");
|
||||
Assert.That(deathVfx, Is.Not.Null);
|
||||
createdObjects.Add(deathVfx);
|
||||
Assert.That(deathVfx.transform.position, Is.EqualTo(spawnPosition));
|
||||
Assert.That(deathVfx.GetComponent<ParticleSystem>(), Is.Not.Null);
|
||||
|
||||
// 4. Тест SpawnPrizeEffect
|
||||
vfxService.SpawnPrizeEffect(spawnPosition);
|
||||
var prizeVfx = GameObject.Find("VFX_PrizeWin");
|
||||
Assert.That(prizeVfx, Is.Not.Null);
|
||||
createdObjects.Add(prizeVfx);
|
||||
Assert.That(prizeVfx.transform.position, Is.EqualTo(spawnPosition));
|
||||
Assert.That(prizeVfx.GetComponent<ParticleSystem>(), Is.Not.Null);
|
||||
|
||||
// 5. Тест SpawnComErrorEffect
|
||||
vfxService.SpawnComErrorEffect(spawnPosition);
|
||||
var comErrorVfx = GameObject.Find("VFX_ComError");
|
||||
Assert.That(comErrorVfx, Is.Not.Null);
|
||||
createdObjects.Add(comErrorVfx);
|
||||
Assert.That(comErrorVfx.transform.position, Is.EqualTo(spawnPosition));
|
||||
Assert.That(comErrorVfx.GetComponent<ParticleSystem>(), Is.Not.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Tests/EditMode/Editor/VfxServiceTests.cs.meta
Normal file
2
Assets/Tests/EditMode/Editor/VfxServiceTests.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2a035f72fca7b44286e836092bc3cbf
|
||||
Loading…
x
Reference in New Issue
Block a user