Skip to content

Commit 6db9da5

Browse files
Fix play mode test issues and refactor test code (#551)
* Fix play mode test scene jumping issue This commit fixes an issue where play mode tests would jump to the init scene but not run any tests. Changes: - Wrap TestRunnerCallbacks.IsRunningTests check with #if UNITY_INCLUDE_TESTS in ChangeScene.cs This ensures the test runner check is only performed when test framework is available - Add test assembly reference to JEngine.Core.Editor.asmdef (GUID:0acc523941302664db1f4e527237feb3) - Update .gitignore to exclude Claude-generated files The root cause was that ChangeScene.cs was trying to check TestRunnerCallbacks.IsRunningTests without verifying the test framework was available, which could cause the check to fail or not work properly during play mode tests. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Improve play mode test detection by preventing RuntimeInitializeOnLoadMethod registration The previous fix checked TestRunnerCallbacks.IsRunningTests at runtime, but there was a timing issue - RuntimeInitializeOnLoadMethod executes before TestRunnerCallbacks.RunStarted is called, so the flag was not set yet. This commit uses the cleaner approach recommended by Unity: prevent the method from being registered at all during tests by applying #if !UNITY_INCLUDE_TESTS to the attribute itself. This eliminates the runtime check and TestRunnerCallbacks dependency entirely from ChangeScene.cs, making the code simpler and more reliable. References: - Unity Discussions: RuntimeInitializeOnLoadMethod runs during playmode unit tests https://discussions.unity.com/t/methods-with-runtimeinitializeonloadmethod-attribute-run-during-playmode-unit-tests/949876 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Detect play mode tests by checking scene name instead of timing-dependent callbacks The previous approaches had timing issues - TestRunnerCallbacks.RunStarted is called after RuntimeInitializeOnLoadMethod, and #if !UNITY_INCLUDE_TESTS doesn't work because the assembly always has UNITY_INCLUDE_TESTS defined (it contains test files). This commit uses a simple, reliable approach: Unity Test Framework creates temporary scenes with names like "InitTestScene<timestamp>" when running play mode tests. By checking if the current scene name starts with "InitTestScene", we can reliably detect test runs at runtime without timing dependencies. Benefits: - No timing issues with callbacks - No dependency on preprocessor directives - Works in all scenarios (GUI test runner, command line, etc.) - Simple and maintainable Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Add Unity Test Framework temporary test scenes to .gitignore Unity Test Framework creates temporary scenes like InitTestScene<timestamp>.unity when running play mode tests. These should not be committed to the repository. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Refactor test code to use simplified lambda expressions and improve code clarity - Simplified lambda expressions by removing explicit parameter types - Added missing using statements for System.Collections.Generic and System.Reflection - Removed redundant System namespace prefixes - Changed DelayFrame(1) to DelayFrame() for default behavior - Minor code cleanup for better readability Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f85eaa7 commit 6db9da5

2 files changed

Lines changed: 46 additions & 42 deletions

File tree

UnityProject/Packages/com.jasonxudeveloper.jengine.util/Tests/Editor/JActionTests.cs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// JActionTests.cs
22
// EditMode unit tests for JAction (synchronous execution)
33

4+
using System.Collections.Generic;
5+
using System.Reflection;
46
using NUnit.Framework;
57

68
namespace JEngine.Util.Tests
@@ -92,7 +94,7 @@ public void Do_WithState_PassesStateToAction()
9294
int result = 0;
9395

9496
JAction.Create()
95-
.Do((int x) => result = x, 42)
97+
.Do(x => result = x, 42)
9698
.Execute();
9799

98100
Assert.AreEqual(42, result);
@@ -105,7 +107,7 @@ public void Do_WithReferenceState_PassesStateToAction()
105107
int result = 0;
106108

107109
JAction.Create()
108-
.Do((TestData d) => result = d.Value, data)
110+
.Do(d => result = d.Value, data)
109111
.Execute();
110112

111113
Assert.AreEqual(10, result);
@@ -129,7 +131,7 @@ public void Repeat_WithState_PassesStateEachTime()
129131
int sum = 0;
130132

131133
JAction.Create()
132-
.Repeat((int x) => sum += x, state: 10, count: 3)
134+
.Repeat(x => sum += x, state: 10, count: 3)
133135
.Execute();
134136

135137
Assert.AreEqual(30, sum);
@@ -156,8 +158,8 @@ public void Cancel_InvokesOnCancelCallback()
156158

157159
// Force executing state and cancel
158160
typeof(JAction).GetField("IsExecuting",
159-
System.Reflection.BindingFlags.NonPublic |
160-
System.Reflection.BindingFlags.Instance)
161+
BindingFlags.NonPublic |
162+
BindingFlags.Instance)
161163
?.SetValue(action2, true);
162164

163165
action2.Cancel();
@@ -173,12 +175,12 @@ public void Cancel_WithState_PassesStateToCallback()
173175
int result = 0;
174176

175177
var action = JAction.Create()
176-
.OnCancel((int x) => result = x, 42);
178+
.OnCancel(x => result = x, 42);
177179

178180
// Force executing state
179181
typeof(JAction).GetField("IsExecuting",
180-
System.Reflection.BindingFlags.NonPublic |
181-
System.Reflection.BindingFlags.Instance)
182+
BindingFlags.NonPublic |
183+
BindingFlags.Instance)
182184
?.SetValue(action, true);
183185

184186
action.Cancel();
@@ -293,7 +295,7 @@ public void Do_WithIntState_WorksCorrectly()
293295
int result = 0;
294296

295297
JAction.Create()
296-
.Do((int x) => result = x, 123)
298+
.Do(x => result = x, 123)
297299
.Execute();
298300

299301
Assert.AreEqual(123, result);
@@ -305,7 +307,7 @@ public void Do_WithFloatState_WorksCorrectly()
305307
float result = 0;
306308

307309
JAction.Create()
308-
.Do((float x) => result = x, 3.14f)
310+
.Do(x => result = x, 3.14f)
309311
.Execute();
310312

311313
Assert.AreEqual(3.14f, result, 0.001f);
@@ -317,7 +319,7 @@ public void Do_WithBoolState_WorksCorrectly()
317319
bool result = false;
318320

319321
JAction.Create()
320-
.Do((bool x) => result = x, true)
322+
.Do(x => result = x, true)
321323
.Execute();
322324

323325
Assert.IsTrue(result);
@@ -349,8 +351,8 @@ public void Dispose_DuringExecution_CancelsFirst()
349351

350352
// Start execution
351353
typeof(JAction).GetField("IsExecuting",
352-
System.Reflection.BindingFlags.NonPublic |
353-
System.Reflection.BindingFlags.Instance)
354+
BindingFlags.NonPublic |
355+
BindingFlags.Instance)
354356
?.SetValue(action, true);
355357

356358
action.Dispose();
@@ -378,7 +380,7 @@ public void Execute_WithNullAction_SkipsGracefully()
378380
[Test]
379381
public void ComplexChain_ExecutesInOrder()
380382
{
381-
var order = new System.Collections.Generic.List<int>();
383+
var order = new List<int>();
382384

383385
JAction.Create()
384386
.Do(() => order.Add(1))
@@ -402,10 +404,10 @@ public void ComplexChain_WithState_PassesCorrectState()
402404
int sum = 0;
403405

404406
JAction.Create()
405-
.Do((int x) => sum += x, 1)
406-
.Do((int x) => sum += x, 10)
407-
.Repeat((int x) => sum += x, state: 100, count: 2)
408-
.Do((int x) => sum += x, 1000)
407+
.Do(x => sum += x, 1)
408+
.Do(x => sum += x, 10)
409+
.Repeat(x => sum += x, state: 100, count: 2)
410+
.Do(x => sum += x, 1000)
409411
.Execute();
410412

411413
Assert.AreEqual(1211, sum); // 1 + 10 + 100 + 100 + 1000
@@ -414,15 +416,15 @@ public void ComplexChain_WithState_PassesCorrectState()
414416
[Test]
415417
public void ComplexChain_MixedStaticAndState_WorksCorrectly()
416418
{
417-
var results = new System.Collections.Generic.List<string>();
419+
var results = new List<string>();
418420

419421
// Mix static lambdas (no closure) with state overloads
420422
using var action = JAction.Create()
421423
.Do(static () => { }) // static lambda, no state needed
422-
.Do(static (System.Collections.Generic.List<string> r) => r.Add("step1"), results)
424+
.Do(static r => r.Add("step1"), results)
423425
.Delay(0.01f)
424-
.Do(static (System.Collections.Generic.List<string> r) => r.Add("step2"), results)
425-
.Repeat(static (System.Collections.Generic.List<string> r) => r.Add("repeat"), results, count: 2)
426+
.Do(static r => r.Add("step2"), results)
427+
.Repeat(static r => r.Add("repeat"), results, count: 2)
426428
.Execute();
427429

428430
Assert.AreEqual(4, results.Count);
@@ -437,7 +439,7 @@ public void Using_AutoDisposesAction()
437439
{
438440
int initialPoolCount = JAction.PooledCount;
439441

440-
using (var action = JAction.Create().Do(() => { }).Execute())
442+
using (JAction.Create().Do(() => { }).Execute())
441443
{
442444
Assert.AreEqual(initialPoolCount, JAction.PooledCount);
443445
}
@@ -457,7 +459,7 @@ public void WaitUntil_WithState_PassesStateToCondition()
457459
bool completed = false;
458460

459461
JAction.Create()
460-
.WaitUntil((TestData d) =>
462+
.WaitUntil(d =>
461463
{
462464
d.Value++;
463465
return d.Value >= 3;
@@ -476,7 +478,7 @@ public void WaitWhile_WithState_PassesStateToCondition()
476478
bool completed = false;
477479

478480
JAction.Create()
479-
.WaitWhile((TestData d) =>
481+
.WaitWhile(d =>
480482
{
481483
d.Value++;
482484
return d.Value < 3;
@@ -496,8 +498,8 @@ public void RepeatWhile_WithState_PassesStateToActionAndCondition()
496498

497499
JAction.Create()
498500
.RepeatWhile(
499-
(TestData d) => { actionCount++; d.Value++; },
500-
(TestData d) => d.Value < 5,
501+
d => { actionCount++; d.Value++; },
502+
d => d.Value < 5,
501503
data)
502504
.Execute();
503505

@@ -513,8 +515,8 @@ public void RepeatUntil_WithState_PassesStateToActionAndCondition()
513515

514516
JAction.Create()
515517
.RepeatUntil(
516-
(TestData d) => { actionCount++; d.Value++; },
517-
(TestData d) => d.Value >= 5,
518+
d => { actionCount++; d.Value++; },
519+
d => d.Value >= 5,
518520
data)
519521
.Execute();
520522

UnityProject/Packages/com.jasonxudeveloper.jengine.util/Tests/Runtime/JActionRuntimeTests.cs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// JActionRuntimeTests.cs
22
// PlayMode tests for JAction (require Unity frame execution)
33

4+
using System;
45
using System.Collections;
6+
using System.Collections.Generic;
57
using System.Threading.Tasks;
68
using NUnit.Framework;
79
using UnityEngine;
@@ -27,7 +29,7 @@ public void TearDown()
2729
/// <summary>
2830
/// Helper to run async code in coroutine context and wait for completion.
2931
/// </summary>
30-
private IEnumerator RunAsync(System.Func<Task> asyncFunc)
32+
private IEnumerator RunAsync(Func<Task> asyncFunc)
3133
{
3234
var task = asyncFunc();
3335

@@ -192,7 +194,7 @@ public IEnumerator ExecuteAsync_CanBeAwaited()
192194
{
193195
using var action = await JAction.Create()
194196
.Do(() => step1 = true)
195-
.DelayFrame(1)
197+
.DelayFrame()
196198
.Do(() => step2 = true)
197199
.ExecuteAsync();
198200

@@ -277,7 +279,7 @@ public IEnumerator WaitUntil_WithState_PassesState()
277279
return RunAsync(async () =>
278280
{
279281
using var action = await JAction.Create()
280-
.WaitUntil(static (TestData d) =>
282+
.WaitUntil(static d =>
281283
{
282284
d.Counter++;
283285
return d.Counter >= 3;
@@ -300,8 +302,8 @@ public IEnumerator RepeatWhile_WithState_PassesState()
300302
{
301303
using var action = await JAction.Create()
302304
.RepeatWhile(
303-
static (TestData d) => d.Counter++,
304-
static (TestData d) => d.Counter < 5,
305+
static d => d.Counter++,
306+
static d => d.Counter < 5,
305307
data)
306308
.Do(() => completed = true)
307309
.ExecuteAsync();
@@ -318,13 +320,13 @@ public IEnumerator RepeatWhile_WithState_PassesState()
318320
[UnityTest]
319321
public IEnumerator ComplexChain_Async_ExecutesInOrder()
320322
{
321-
var order = new System.Collections.Generic.List<int>();
323+
var order = new List<int>();
322324

323325
return RunAsync(async () =>
324326
{
325327
using var action = await JAction.Create()
326328
.Do(() => order.Add(1))
327-
.DelayFrame(1)
329+
.DelayFrame()
328330
.Do(() => order.Add(2))
329331
.Delay(0.05f)
330332
.Do(() => order.Add(3))
@@ -345,18 +347,18 @@ public IEnumerator ComplexChain_Async_ExecutesInOrder()
345347
[UnityTest]
346348
public IEnumerator ComplexChain_Async_WithStaticLambdasAndState()
347349
{
348-
var results = new System.Collections.Generic.List<string>();
350+
var results = new List<string>();
349351
bool completed = false;
350352

351353
return RunAsync(async () =>
352354
{
353355
// Mix static lambdas with state overloads - zero closure allocations
354356
using var action = await JAction.Create()
355-
.Do(static (System.Collections.Generic.List<string> r) => r.Add("start"), results)
356-
.DelayFrame(1)
357-
.Do(static (System.Collections.Generic.List<string> r) => r.Add("after_frame"), results)
357+
.Do(static r => r.Add("start"), results)
358+
.DelayFrame()
359+
.Do(static r => r.Add("after_frame"), results)
358360
.Delay(0.05f)
359-
.Repeat(static (System.Collections.Generic.List<string> r) => r.Add("repeat"), results, count: 2)
361+
.Repeat(static r => r.Add("repeat"), results, count: 2)
360362
.Do(() => completed = true) // This one has closure (for test verification)
361363
.ExecuteAsync();
362364

@@ -384,7 +386,7 @@ public IEnumerator UsingAwait_AutoDisposesAfterExecution()
384386
// Use explicit using block so we can check pool count after disposal
385387
using (var action = await JAction.Create()
386388
.Do(() => completed = true)
387-
.DelayFrame(1)
389+
.DelayFrame()
388390
.ExecuteAsync())
389391
{
390392
Assert.IsTrue(completed);

0 commit comments

Comments
 (0)