unity-tests-write
SKILL.md
Unity Testing Skill
You are a Unity testing specialist using Unity Test Framework.
First Checks
- Read project test setup first (
Packages/manifest.json, asmdef test assemblies, CI scripts, and Unity version constraints) - Verify
com.unity.test-frameworkversion before choosing async test style (IEnumeratorbaseline vsasync Taskin newer UTF versions) - Match existing conventions (test naming, fixture style, and coverage gates) unless the user asks to change them
Test Distribution
- EditMode Tests: Editor code, static analysis, serialization, utilities
- PlayMode Tests: Runtime behavior, MonoBehaviour lifecycle, physics, coroutines, UI
Test Project Structure
Tests/
├── Editor/
│ ├── <Company>.<Package>.Editor.Tests.asmdef
│ └── FeatureTests.cs
└── Runtime/
├── <Company>.<Package>.Tests.asmdef
└── FeaturePlayModeTests.cs
EditMode Test Pattern
using NUnit.Framework;
using UnityEngine;
[TestFixture]
public class FeatureEditorTests
{
[SetUp]
public void Setup()
{
// Arrange common test setup
}
[TearDown]
public void TearDown()
{
// Cleanup
}
[Test]
public void MethodName_Condition_ExpectedResult()
{
// Arrange
var sut = new SystemUnderTest();
var expected = 42;
// Act
var result = sut.DoSomething();
// Assert
Assert.AreEqual(expected, result);
}
}
PlayMode Test Pattern
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
public class FeaturePlayModeTests
{
private GameObject _testObject;
[SetUp]
public void Setup()
{
_testObject = new GameObject("TestObject");
}
[TearDown]
public void TearDown()
{
// Use Destroy for PlayMode tests (DestroyImmediate for EditMode tests)
Object.Destroy(_testObject);
}
[UnityTest]
public IEnumerator ComponentBehavior_AfterOneFrame_ShouldUpdate()
{
// Arrange
var component = _testObject.AddComponent<TestComponent>();
// Act
yield return null; // Wait one frame
// Assert
Assert.IsTrue(component.HasUpdated);
}
[UnityTest]
public IEnumerator AsyncOperation_WhenComplete_ShouldSucceed()
{
// Arrange
var operation = StartAsyncOperation();
// Act
yield return new WaitUntil(() => operation.IsDone);
// Assert
Assert.IsTrue(operation.Success);
}
}
Async Test Compatibility (Task and Awaitable)
- Widest compatibility baseline (including older Unity/UTF): keep
[UnityTest]methods returningIEnumerator - For UTF
1.3+,UnityTestsupportsasync Task; use this for modern async flows where it improves readability - For Unity
2023.1+and Unity6+, you can awaitUnityEngine.Awaitableinside async tests - Do not use
Awaitableas the test method return type; useTaskorIEnumeratorfor test entry points - Await each
Awaitableinstance once only
using System.Threading.Tasks;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
public class FeatureAsyncPlayModeTests
{
[UnityTest]
public async Task ComponentBehavior_AfterOneFrame_ShouldUpdate()
{
var go = new GameObject("TestObject");
var component = go.AddComponent<TestComponent>();
#if UNITY_6000_0_OR_NEWER
await Awaitable.NextFrameAsync();
#else
await Task.Yield();
#endif
Assert.IsTrue(component.HasUpdated);
Object.Destroy(go);
}
}
Performance Testing
Use Unity Performance Testing package for critical paths:
using NUnit.Framework;
using Unity.PerformanceTesting;
using UnityEngine;
public class PerformanceTests
{
[Test, Performance]
public void MyMethod_Performance()
{
Measure.Method(() =>
{
// Code to measure
MyExpensiveMethod();
})
.WarmupCount(10)
.MeasurementCount(100)
.Run();
}
[Test, Performance]
public void Update_Performance()
{
var go = new GameObject();
var component = go.AddComponent<MyComponent>();
Measure.Frames()
.WarmupCount(10)
.MeasurementCount(100)
.Run();
Object.DestroyImmediate(go);
}
}
Code Coverage
Use Unity Code Coverage package (com.unity.testtools.codecoverage):
Coverage Targets:
- Use project-defined thresholds first
- If no threshold exists, use >=80% for critical business logic as a default baseline
Running with coverage:
Unity -batchmode -projectPath "$(pwd)" -runTests -testPlatform EditMode -enableCodeCoverage -coverageResultsPath ./CodeCoverage -testResults ./TestResults/editmode.xml -quit
Testing Best Practices
Do
- Use
[SetUp]and[TearDown]for consistent test isolation - Test one behavior per test method
- Use descriptive test names:
MethodName_Condition_ExpectedResult(e.g.,GetUser_WhenNotFound_ReturnsNull) - Mock external dependencies when possible
- Use
UnityEngine.TestTools.LogAssertto verify expected log messages
Don't
- Share mutable state between tests
- Rely on test execution order
- Test Unity's own functionality
- Leave test GameObjects in scene after tests
Arrange-Act-Assert Pattern
Always structure tests as:
[Test]
public void MethodName_Condition_ExpectedResult()
{
// Arrange - Setup test data and dependencies
var input = CreateTestInput();
var expected = CreateExpectedOutput();
// Act - Execute the code under test
var result = systemUnderTest.Process(input);
// Assert - Verify the outcome
Assert.AreEqual(expected, result);
}
Weekly Installs
1
Repository
dmitriyyukhanov…-pluginsGitHub Stars
2
First Seen
6 days ago
Security Audits
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1