unity-test-framework
Author and run the Unity game-engine Test Framework (`com.unity.test-framework`, currently v1.8). Distinct from the ThrowTheSwitch Unity C testing library at throwtheswitch.org/unity - the two tools share only a name. Covers package install via Package Manager, the EditMode vs PlayMode split, the [Test] / [UnityTest] / [SetUp] / [TearDown] / [UnityPlatform] attributes, assembly-definition setup (Editor folder vs asmdef with `includePlatforms` / `optionalUnityReferences: [TestAssemblies]`), Test Runner window, command-line batch invocation with `-runTests` / `-testPlatform` / `-testResults` / `-testFilter` / `-testCategory`, NUnit 3.5 assertion API, and CI integration. Use when the unit under test is C# Unity code that needs to exercise the Unity runtime or editor.
Install with skills.sh (any agent)
npx skills add testland/qa --skill unity-test-frameworkunity-test-framework
Overview
Disambiguation up front. This skill covers the Unity game-engine Test Framework - the official Unity package com.unity.test-framework documented at docs.unity3d.com/Packages/com.unity.test-framework@latest (opens in new window). It is distinct from the ThrowTheSwitch Unity C testing library at throwtheswitch.org/unity (opens in new window) (a single-C-file unit-test framework for bare-metal MCUs). The two tools share only a name; they have unrelated origins, APIs, and consumers. For the C unit-test library, see the sibling skill unity-test-framework-c in the qa-embedded plugin.
UTF is built on NUnit 3.5 and supports both Edit Mode and Play Mode across Standalone, Android, and iOS target platforms (per the package overview (opens in new window)).
Versioning. UTF is currently v1.8; the stable doc links below pin to the v1.4 manual snapshot for durable URLs. Both describe the same package.
Composes with:
When to use
For C unit tests on the firmware side of a hybrid game build, use unity-test-framework-c instead.
Authoring
Install via Package Manager
UTF "is shipped with the Unity Editor and should be automatically included in any project created with Unity 2019.2 or later" (per the package overview). For manual install, open Package Manager → + → "Add package by name…" → com.unity.test-framework.
The Test Runner window is at Window → General → Test Runner (may be Window → Test Runner depending on Editor version).
EditMode tests
Per the Edit Mode vs Play Mode tests page (opens in new window), Edit Mode tests "are only run in the Unity Editor and have access to the Editor code in addition to the game code".
Layout (two options):
Minimal example:
using NUnit.Framework;
using UnityEngine;
namespace MyGame.Tests.EditMode
{
public class HealthComponentTests
{
[Test]
public void Damage_DeductsCorrectAmount()
{
var go = new GameObject();
var health = go.AddComponent<HealthComponent>();
health.Initialize(maxHealth: 100);
health.ApplyDamage(35);
Assert.AreEqual(65, health.Current);
}
[TearDown]
public void Cleanup()
{
// EditMode tests must clean up created GameObjects;
// they don't auto-tear-down between cases.
}
}
}The docs recommend the NUnit Test attribute rather than UnityTest unless you need to yield special instructions in Edit Mode, or skip a frame / wait for an amount of time in Play Mode.
PlayMode tests
PlayMode tests "execute as coroutines within the game runtime and can run standalone in a Player or within the Editor". Assembly definition:
{
"name": "MyGame.Tests.PlayMode",
"references": ["MyGame.Runtime"],
"optionalUnityReferences": ["TestAssemblies"],
"includePlatforms": []
}Per the edit-mode-vs-play-mode docs, the .asmdef must reference the code under test ("references": ["NewAssembly"]), optionally include "optionalUnityReferences": ["TestAssemblies"], and leave "includePlatforms": [] empty to allow multiple target platforms.
Minimal example:
using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace MyGame.Tests.PlayMode
{
public class EnemyAITests
{
[UnityTest]
public IEnumerator Enemy_PursuesPlayer_WithinRange()
{
var player = new GameObject("Player");
var enemy = Object.Instantiate(Resources.Load<GameObject>("Enemy"));
enemy.transform.position = new Vector3(10f, 0f, 0f);
yield return new WaitForSeconds(2f);
var distance = Vector3.Distance(player.transform.position,
enemy.transform.position);
Assert.Less(distance, 5f, "Enemy did not close on player");
}
}
}The [UnityTest] attribute, returning IEnumerator, lets the test yield frames (yield return null), seconds (yield return new WaitForSeconds(2f)), or custom yield instructions - necessary for any frame-driven behaviour.
Attributes
The common attributes are [Test] (synchronous NUnit), [UnityTest] (coroutine, yields frames/seconds), [SetUp] / [TearDown], [OneTimeSetUp] / [OneTimeTearDown], [Category("Smoke")] (CLI-selectable), and [UnityPlatform(...)]. The full cheatsheet with sources and the ValueSource parameterisation note is in references/attributes.md.
NUnit assertion APIs
UTF is built on NUnit 3.5, so the full NUnit 3 assertion model applies - Assert.AreEqual, Assert.Throws<T>(() => ...), Assert.That(actual, Is.EqualTo(expected).Within(0.01f)), etc. Prefer the NUnit Test attribute over UnityTest unless you need to yield special instructions.
Running
From the Test Runner window
Window → General → Test Runner (path may be Window → Test Runner in older Editor versions). The window shows two tabs:
Click Run All, Run Selected, or right-click a fixture → Run to execute. Results display inline with stack traces on failure.
From the command line (batch mode)
Invoke Unity in batch mode and treat the -testResults XML as the source of truth (Unity has no common exit-code definition):
Unity \
-batchmode \
-projectPath "$PWD" \
-runTests \
-testPlatform PlayMode \
-testResults artifacts/playmode-results.xml \
-testCategory "Smoke" \
-logFile artifacts/unity.logThe full batch-mode flag table (-testFilter, -testPlatform, -assemblyNames, ordering / retry flags), the Windows invocation, and the exit-code caveat are in references/cli.md.
Parsing results
The -testResults XML is NUnit 3 result format. Surface result="Failed" at the <test-run> level for the overall verdict, then enumerate <test-case result="Failed"> for per-test detail; nunit-junit-xml converters exist for JUnit consumers. The full schema example is in references/results-and-ci.md.
CI integration
Run UTF in CI via game-ci/unity-test-runner (or the bare batch-mode CLI), upload the -testResults XML as an artifact, and cache the Library/ folder across runs - Unity re-imports all assets without it, adding 5 - 15 min per run. A complete GitHub Actions workflow is in references/results-and-ci.md.
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Using [UnityTest] everywhere | Slower than [Test] because each test enters play mode | Use [Test] unless you need to yield (per the edit-mode-vs-play-mode docs) |
Forgetting optionalUnityReferences: ["TestAssemblies"] | Test assembly isn't picked up by Test Runner | Add it per the PlayMode asmdef block above |
| Test asmdef references production asmdef but production has no public types | Tests can't compile | Use InternalsVisibleTo on production asmdef or expose minimal public surface |
Not cleaning up GameObjects between EditMode tests | Cross-test contamination | [TearDown] Object.DestroyImmediate(go) on every fixture |
| Trusting Unity process exit code in CI | No common definition for exit codes | Parse -testResults XML in CI |
Skipping the Library/ cache | 5 - 15 min asset reimport per CI run | actions/cache@v4 with the Library/ path |
| Confusing this skill with ThrowTheSwitch Unity (C) | Different tool with the same name | See unity-test-framework-c |
Limitations
Known constraints (per the v1.4 manual index):
Other practical limitations:
UTF attribute cheatsheet - reference
View source (opens in new window)UTF attribute cheatsheet - reference
Attributes for unity-test-framework, per the v1.4 manual index (opens in new window) and the NUnit 3.5 docs the framework wraps.
| Attribute | Purpose | Source |
|---|---|---|
[Test] | Plain NUnit test - synchronous | NUnit; recommended default per edit-mode-vs-play-mode docs |
[UnityTest] | Coroutine-style test that can yield frames / seconds in PlayMode or skip frames in EditMode | UTF-specific |
[SetUp] / [TearDown] | Per-test fixture setup / cleanup | NUnit |
[OneTimeSetUp] / [OneTimeTearDown] | Once-per-fixture setup / cleanup | NUnit |
[TestFixture] | Marks a class as containing tests (optional in NUnit 3) | NUnit |
[Category("Smoke")] | Tag a test for filtering | NUnit; selectable via CLI -testCategory |
[UnityPlatform(RuntimePlatform.WindowsPlayer)] | Restrict test to specific runtime platforms | UTF-specific |
[ValueSource(nameof(MyCases))] | Parameterised inputs | NUnit; ValueSource is supported per the v1.4 manual (other parameterised attributes have known limitations - see the skill's Limitations section) |
UTF command-line (batch mode) - reference
View source (opens in new window)UTF command-line (batch mode) - reference
Batch-mode flags and the exit-code caveat for unity-test-framework, per the command-line reference (opens in new window).
Flags
| Flag | Effect |
|---|---|
-runTests | "Executes tests within the project." |
-batchmode | "Removes the need for manual user inputs when running tests from the command line." |
-projectPath <path> | Project root. |
-testResults <path> | "Designates where Unity stores the result file (XML format per NUnit standards). If unspecified, results are saved in the project root." |
-testPlatform EditMode|PlayMode|<BuildTarget> | "Default: EditMode if not specified." BuildTarget (e.g. StandaloneWindows64, Android) runs tests on a built player for that platform. |
-testFilter "Pattern" | "Accepts a semicolon-separated list or regex pattern to match test names. Supports negation with !." |
-testCategory "Smoke;Critical" | "Accepts a semicolon-separated list or regex pattern for category matching. Also supports negation with !." |
-assemblyNames "MyGame.Tests.PlayMode" | Limit to specific test assemblies. |
-runSynchronously | Run on the main thread synchronously (EditMode only). |
-orderedTestListFile, -randomOrderSeed, -retry, -repeat, -playerHeartbeatTimeout, -testSettingsFile | "Control test execution order, failure handling, timing, and settings configuration" per the same page. |
Full example (Linux / macOS)
Unity \
-batchmode \
-projectPath "$PWD" \
-runTests \
-testPlatform PlayMode \
-testResults artifacts/playmode-results.xml \
-testCategory "Smoke" \
-logFile artifacts/unity.logWindows equivalent: invoke "C:\Program Files\Unity\Hub\Editor\<version>\Editor\Unity.exe" with the same flags.
Exit-code caveat
Per the command-line reference: "There is currently no common definition for exit codes reported by individual Unity components under test. Error messages and stack traces in results provide better diagnostic information." Treat the produced -testResults XML as the source of truth in CI rather than the process exit code.
UTF result parsing and CI - reference
View source (opens in new window)UTF result parsing and CI - reference
NUnit 3 result format and CI wiring for unity-test-framework.
NUnit 3 result XML
The XML written to -testResults <path> is NUnit 3 result format. The CI pipeline must parse it to surface failures. Top-level structure:
<test-run id="2" testcasecount="42" result="Failed" total="42"
passed="40" failed="1" inconclusive="0" skipped="1">
<test-suite ...>
<test-case fullname="MyGame.Tests.HealthTests.Damage_DeductsCorrectAmount"
result="Passed" duration="0.012"/>
<test-case fullname="MyGame.Tests.EnemyAITests.Enemy_PursuesPlayer_WithinRange"
result="Failed" duration="2.34">
<failure>
<message><![CDATA[Enemy did not close on player]]></message>
<stack-trace><![CDATA[at MyGame.Tests.EnemyAITests...]]></stack-trace>
</failure>
</test-case>
</test-suite>
</test-run>Surface result="Failed" at the <test-run> level for the overall pass / fail, then enumerate <test-case result="Failed"> for per-test detail. The schema is NUnit-canonical - nunit-junit-xml converters exist for tools that expect JUnit XML.
GitHub Actions
Using game-ci/unity-test-runner:
jobs:
unity-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: true
- uses: actions/cache@v4
with:
path: Library
key: Library-${{ github.sha }}
restore-keys: Library-
- uses: game-ci/unity-test-runner@v4
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
testMode: all # editmode + playmode
artifactsPath: artifacts
coverageOptions: "generateAdditionalMetrics;generateHtmlReport"
- uses: actions/upload-artifact@v4
if: always()
with:
name: unity-test-results
path: artifacts/**/*.xmlCache the Library/ folder across runs - Unity re-imports all assets without it, adding 5 - 15 min per CI run. The bare-CLI equivalent invokes Unity directly with the flags in cli.md (opens in new window) and treats the -testResults XML as the source of truth.
Related skills
game-perf-profiling
Profiles game builds against frame-time, memory, GPU draw-call, and GC-spike budgets using Unity Profiler + Profile Analyzer + Performance Testing package and Unreal Insights + stat commands. Establishes pass/fail thresholds (16.6 ms at 60 fps, 33.3 ms at 30 fps), writes automated performance regression tests that run in CI, and emits a structured budget report per SKU. Use when a title must hit a declared frame-time or memory budget before a milestone gate or platform-cert submission, or when a recent change needs a performance regression check.
game-test-categories-reference
Pure-reference catalog of the testing categories that apply to a video-game build before it ships. Defines the six canonical buckets the industry tests against - functional / compliance / compatibility / performance / localization / accessibility - plus the multiplayer and content-rating sub-axes. Cross-references each bucket to the platform-holder vocabulary that drives it (Microsoft Xbox Requirements / XR test cases, Sony TRC, Nintendo Lotcheck, Steam Direct review). Use as the taxonomy lookup when planning a game test pass, scoping QA effort, mapping platform-cert findings back to internal test categories, preparing a submission checklist, reviewing first-party certification requirements, or triaging cert testing failures against internal categories.
gameplay-recording-replay
Build a deterministic gameplay record/replay test artefact for Unity, Unreal, or Godot - record a player session, save it to disk, replay it bit-for-bit, and assert that the resulting game state matches the original. Covers Unity Input System's InputEventTrace API (Enable / Disable / WriteTo / ReadFrom / Replay) for input-level capture, Unreal's Replay System (DemoRec / DemoPlay / DemoStop console commands plus DemoNetDriver + NetworkReplayStreamer, default storage at %LOCALAPPDATA%/{Project}/Saved/Demos) for replication-stream capture, and Godot's community-pattern deterministic-RNG + input-script replay since Godot ships no first-party replay system. Use when authoring a regression-test artefact for player-recorded sessions, building a netcode replay for spectator / esports, or producing reproducible bug repros for cert teams.
godot-gut-tests
Author and run GUT (Godot Unit Test) - the community-canonical GDScript test framework at github.com/bitwes/Gut and gut.readthedocs.io. Covers install (Godot Asset Library or manual `addons/gut/` copy + plugin enable), GUT panel inside the editor, writing tests that extend GutTest with `test_` prefix methods, the assertion family (assert_eq / assert_almost_eq / assert_true / assert_signal_emitted), lifecycle hooks (before_each / after_each / before_all / after_all), inner classes for grouping, parameterized tests via `params=[...]`, doubles / stubs / spies, async / coroutine tests, the command-line runner (`-d -s addons/gut/gut_cmdln.gd -gdir=res://test -gjunit_xml_file=... -gexit`), JUnit XML export, and CI integration. Godot 4.x uses GUT 9.x (current main branch supports 4.6.x; godot_4_7 branch for 4.7.x); Godot 3.x uses GUT 7.x. Use when the unit under test is GDScript code in a Godot project.
multiplayer-state-machine-coverage
Build a coverage matrix for a networked-game state machine that exercises connect / authority-handoff / disconnect / reconnect / host-migration paths across Unity Netcode for GameObjects, Unreal Engine replication, and Mirror Networking. Workflow: enumerate the engine's connection states + ownership states + replicated-property update rules, cross them against latency / loss / out-of-order packet injection, encode each combination as a test fixture, and emit a go / no-go gate. Use before submitting a multiplayer title to platform cert - Microsoft's cert guide lists 'Multiplayer does not work as expected' as one of the most common Hold reasons, and Xbox XR-067 (MPSD session state) is failed by uncovered state-machine paths.
platform-cert-overview-reference
Pure-reference catalog of the four platform-holder certification regimes a multi-platform title submits to before release: Microsoft Xbox Requirements (XR) / Xbox certification on learn.microsoft.com, Sony Technical Requirements Checklist (TRC) on the gated PlayStation DevNet portal, Nintendo Lotcheck on the gated Nintendo Developer Portal, and Steam Direct review on partner.steamgames.com. Documents the submission workflow, severity / pass-fail vocabulary, test-bench configurations, and known SLAs for each platform. Cites public sources inline; cites gated NDA portals by stable ID per PLUGIN_AUTHORING.md Step 4 fallback. Use when planning a cert calendar, mapping internal QA findings to the platform's vocabulary, or sequencing submissions across platforms.
unreal-automation-system
Author and run Unreal Engine's Automation Test Framework - Epic's C++ test framework for UE 4.x / 5.x, documented at dev.epicgames.com/documentation/en-us/unreal-engine. Covers the five test categories Epic defines (Unit / Feature / Smoke / Content Stress / Screenshot Comparison), the IMPLEMENT_SIMPLE_AUTOMATION_TEST and IMPLEMENT_COMPLEX_AUTOMATION_TEST macros, the BDD-style Automation Spec API (DEFINE_SPEC / BEGIN_DEFINE_SPEC / Describe / It / BeforeEach / LatentIt / xIt), latent commands (ADD_LATENT_AUTOMATION_COMMAND), the Automation Driver for UI input simulation (IAutomationDriverModule::Get().CreateDriver(), By::Id / By::Path locators), running via Session Frontend (Window > Test Automation) and command line (-ExecCmds="Automation RunTests …"), and CI integration. Use when the unit under test is C++ Unreal code that needs the UE runtime, editor, or UMG UI surface.