本文へ移動
cccskills
無料GitHub で公開

unity-testing

Use when writing or running Unity tests - Unity Test Framework EditMode vs PlayMode, test assembly definitions, testing plain C# and ScriptableObjects, PlayMode scene/physics/input tests, batchmode CLI with result XML, coverage, and the dotnet test fallback when no editor is installed.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Unity Testing

Overview

The Unity Test Framework (NUnit 3 underneath) runs tests in two modes. EditMode tests run in the editor without entering Play mode — fast, ideal for plain C# rules, ScriptableObjects and editor tooling. PlayMode tests run the player loop — needed for scenes, physics, coroutines and input, and slower. Most tests should be EditMode tests against plain classes (testable-game-logic).

Core principle: EditMode first; PlayMode only for behaviour that needs the player loop. Read the result XML, not the log tail.

Which mode

QuestionModeTypical setup
Does the damage/cooldown/inventory rule compute correctly?EditModenew the plain class
Is every shipped definition valid?EditModeAssetDatabase.FindAssets
Does a ScriptableObject-driven system behave?EditModeScriptableObject.CreateInstance<T>()
Does the character land on the floor / trigger fire?PlayModeload a test scene, WaitForFixedUpdate
Does pressing Jump jump?PlayModeInputTestFixture
Does the coroutine/Awaitable sequence finish?PlayMode[UnityTest] yielding frames

Test assemblies

{
  "name": "Tests.EditMode",
  "references": ["Game.Core", "Game.Runtime", "UnityEngine.TestRunner", "UnityEditor.TestRunner"],
  "includePlatforms": ["Editor"],
  "overrideReferences": true,
  "precompiledReferences": ["nunit.framework.dll"],
  "defineConstraints": ["UNITY_INCLUDE_TESTS"],
  "autoReferenced": false
}

PlayMode assemblies leave includePlatforms empty (any platform) and drop UnityEditor.TestRunner unless they need editor APIs. Tests live where the repository keeps them (often Assets/Tests/EditMode and Assets/Tests/PlayMode); follow its naming — Method_Scenario_Expected when there is none.

EditMode examples

public class InventoryTests {
    [Test] public void Add_BeyondStackLimit_OverflowsToNewSlot() {
        var potion = ScriptableObject.CreateInstance<ItemDefinition>();
        potion.Configure(id: "potion", maxStack: 5);
        var inv = new Inventory(slots: 4);

        inv.Add(potion, 7);

        Assert.That(inv.Slots[0].Count, Is.EqualTo(5));
        Assert.That(inv.Slots[1].Count, Is.EqualTo(2));
        Object.DestroyImmediate(potion);
    }

    [TestCase(0f, 100)] [TestCase(0.5f, 50)] [TestCase(1f, 0)]
    public void Damage_ByArmorFraction_ReducesLinearly(float armor, int expected) =>
        Assert.That(DamageMath.Apply(100, armor), Is.EqualTo(expected));
}

Destroy every object a test creates (DestroyImmediate in EditMode, Destroy in PlayMode, or in [TearDown]) — leaked objects leak into the next test.

PlayMode examples

public class PlayerPhysicsTests {
    [UnitySetUp] public IEnumerator Load() { yield return SceneManager.LoadSceneAsync("Test_FlatFloor"); }

    [UnityTest] public IEnumerator Player_DroppedAboveFloor_BecomesGrounded() {
        var player = Object.Instantiate(TestPrefabs.Player, new Vector3(0, 3, 0), Quaternion.identity);
        for (int i = 0; i < 100; i++) yield return new WaitForFixedUpdate();
        Assert.That(player.GetComponent<GroundCheck>().IsGrounded, Is.True);
    }
}

public class JumpInputTests : InputTestFixture {
    [UnityTest] public IEnumerator PressingSpace_MakesPlayerJump() {
        var keyboard = InputSystem.AddDevice<Keyboard>();
        var player = Object.Instantiate(TestPrefabs.Player);
        yield return null;
        Press(keyboard.spaceKey);
        yield return new WaitForFixedUpdate();
        Assert.That(player.GetComponent<Rigidbody>().linearVelocity.y, Is.GreaterThan(0f));
    }
}
  • Use dedicated small test scenes (Test_*.unity) added to the test build, not production levels.
  • Wait on conditions with a cap (for up to N fixed updates) instead of WaitForSeconds guesses.
  • Time.timeScale can speed slow sequences, but physics results change with the step — assert outcomes, not exact positions.

Running headless

UNITY="/Applications/Unity/Hub/Editor/$(sed -n 's/m_EditorVersion: //p' ProjectSettings/ProjectVersion.txt)/Unity.app/Contents/MacOS/Unity"
mkdir -p /tmp/tt-<task key>
"$UNITY" -batchmode -nographics -projectPath . -runTests -testPlatform EditMode \
  -testResults /tmp/tt-<task key>/editmode.xml -logFile /tmp/tt-<task key>/editmode.log
"$UNITY" -batchmode -projectPath . -runTests -testPlatform PlayMode \
  -testResults /tmp/tt-<task key>/playmode.xml -logFile /tmp/tt-<task key>/playmode.log
  • Do not add -quit with -runTests; the editor quits when the run ends.
  • Drop -nographics for PlayMode tests that render or capture (game-visual-self-review).
  • -testFilter "Game.Tests.InventoryTests" or -testCategory narrows a run while iterating.
  • The project must not be open in another editor instance (the lock fails the run).
  • Read the result: grep -o 'result="[A-Za-z]*" total="[0-9]*" passed="[0-9]*" failed="[0-9]*"' editmode.xml | head -1, and grep 'error CS' editmode.log for compile errors (a compile error means zero tests ran, which is not a pass). A non-zero exit code is a failure.
  • Licence errors in the log ("No valid Unity Editor license") mean the run never started — report it as not run.

Coverage, when the Code Coverage package is installed: add -enableCodeCoverage -coverageResultsPath /tmp/tt-<task key>/coverage -coverageOptions "generateAdditionalMetrics;assemblyFilters:+Game.*".

No editor on this machine

  1. Keep the rules in Game.Core (noEngineReferences: true).
  2. Build a throwaway test project outside the repo:
<!-- /tmp/tt-<task key>/core-tests/CoreTests.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>disable</Nullable></PropertyGroup>
  <ItemGroup>
    <Compile Include="<repo>/Assets/Scripts/Core/**/*.cs" />
    <Compile Include="<repo>/Assets/Tests/EditMode/Core/**/*.cs" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
    <PackageReference Include="NUnit" Version="3.*" />
    <PackageReference Include="NUnit3TestAdapter" Version="4.*" />
  </ItemGroup>
</Project>
  1. dotnet test /tmp/tt-<task key>/core-tests — Unity's C# language version is older than .NET 8's default, so set <LangVersion>9.0</LangVersion> if the repo targets it, to avoid using features Unity cannot compile.
  2. Report both: RAN: dotnet test (Core) 18/18 and NOT RUN: EditMode/PlayMode — Unity <version> not installed.

Common Mistakes

  • PlayMode tests for pure rules — slow and flaky for no gain.
  • Tests that depend on production scenes or on execution order between tests.
  • Objects created in a test and never destroyed.
  • Reading "Exiting batchmode successfully" as "tests passed" while the XML says failed or the log shows error CS.

Red Flags

  • A new gameplay rule with only a PlayMode test.
  • WaitForSeconds(2) as the synchronisation in a test.
  • A test assembly that references Game.UI to test gameplay.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation

日本語の概要は準備中です。原文の説明を表示しています。

makifbaysal/tasktrooper1122026年10月10日 更新

makifbaysal のスキルをすべて見る

このスキルの問題を報告する