Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when starting any game task, before writing tests - find out which editors and runners exist on this machine, keep gameplay rules in engine-independent classes with an injected clock and seeded RNG, and report exactly what could not run.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
You run headless on the user's machine. A web game or a Bevy crate can always be built and tested; a Unity, Unreal or Godot editor may or may not be installed, licensed and at the right version. The answer is the same in every engine: gameplay rules live in plain classes that a plain runner can drive, and engine callbacks are thin adapters that feed them input, time and randomness.
Core principle: If a rule can only be tested by pressing Play, it is in the wrong class. And a test you wrote but could not run is reported as exactly that — never as a pass.
Run these first, in one step, and keep the answers for the plan.
# Unity: the exact editor version the project pins
grep m_EditorVersion ProjectSettings/ProjectVersion.txt
ls "/Applications/Unity/Hub/Editor/" 2>/dev/null # macOS
ls "$HOME/Unity/Hub/Editor/" 2>/dev/null # Linux
echo "$UNITY_PATH"
# macOS binary: /Applications/Unity/Hub/Editor/<ver>/Unity.app/Contents/MacOS/Unity
# Windows: C:\Program Files\Unity\Hub\Editor\<ver>\Editor\Unity.exe ; Linux: ~/Unity/Hub/Editor/<ver>/Editor/Unity
# Godot: binary and version must match config/features (major.minor); .NET projects need the .NET build
which godot godot4 2>/dev/null; godot --version 2>/dev/null
ls /Applications/Godot*.app/Contents/MacOS/ 2>/dev/null
# Unreal: EngineAssociation in the .uproject names the install
grep EngineAssociation *.uproject
ls "/Users/Shared/Epic Games/" 2>/dev/null # macOS; Windows: C:\Program Files\Epic Games\UE_5.x
# binary: <engine>/Engine/Binaries/<Mac|Win64|Linux>/UnrealEditor-Cmd
node -v; cargo --version; dotnet --version; python3 --version 2>/dev/null
Rules:
project.godot.run_terminal a long timeout, or run detached to /tmp/tt-<task key>/<step>.log and read the log.Rules (plain C# / GDScript RefCounted / C++ struct / TS module / Rust fn) ← unit tests, any runner
↑ called by
Engine adapter (MonoBehaviour / Node / Actor component / Phaser scene / Bevy system) ← engine tests
↑ wired in
Scenes, prefabs, Blueprints, data assets ← looked at (game-visual-self-review)
The adapter reads input and deltaTime, calls the rule, and applies the result to the engine (transform, animation, UI event). It contains no if about game rules.
// ❌ rule welded to the engine: untestable without Play mode, reads global time
public class Dash : MonoBehaviour {
float _lastDash;
void Update() {
if (Input.GetKeyDown(KeyCode.Space) && Time.time - _lastDash > 1.5f) {
_lastDash = Time.time;
GetComponent<Rigidbody>().AddForce(transform.forward * 20, ForceMode.Impulse);
}
}
}
// ✅ rule in a plain class (assembly with noEngineReferences), time passed in
public sealed class Cooldown {
readonly float _duration; float _remaining;
public Cooldown(float duration) => _duration = duration;
public bool IsReady => _remaining <= 0f;
public void Tick(float dt) => _remaining = MathF.Max(0f, _remaining - dt);
public bool TryConsume() { if (!IsReady) return false; _remaining = _duration; return true; }
}
[Test] public void TryConsume_WhileCoolingDown_ReturnsFalse() {
var c = new Cooldown(1.5f);
Assert.That(c.TryConsume(), Is.True);
c.Tick(1.0f);
Assert.That(c.TryConsume(), Is.False);
c.Tick(0.5f);
Assert.That(c.TryConsume(), Is.True);
}
The adapter DashAbility : MonoBehaviour caches its Rigidbody in Awake, ticks the cooldown in Update with Time.deltaTime, and applies the impulse in FixedUpdate when an input flag is set — three lines with no rule in them.
| Engine | Runs without the editor | How |
|---|---|---|
| Unity | Rules in an asmdef with "noEngineReferences": true | A throwaway net8.0 NUnit project in /tmp/tt-<task key>/ that compiles those sources: <Compile Include="<repo>/Assets/Scripts/Core/**/*.cs" />, then dotnet test. Commit the EditMode test in the repo either way. |
| Godot (C#) | Plain C# classes with no Godot namespace | A class-library project referenced by an xUnit/NUnit project, dotnet test |
| Godot (GDScript) | Nothing — GDScript needs the Godot binary | Write the gdUnit4/GUT test anyway and report it as not run |
| Unreal | Nothing — even pure C++ in a module needs the engine build | Write the Automation Spec anyway and report it as not run |
| Web, Bevy, MonoGame, pygame | Everything | Vitest, cargo test, dotnet test, pytest |
If the repository already has such a plain-runner project (a Tests.Core.csproj, a logic/ crate), use it instead of a throwaway one.
dt (or an IClock), never read Time.time, OS.get_ticks_msec(), performance.now() or Instant::now() themselves.new System.Random(seed), RandomNumberGenerator with .seed, a mulberry32(seed) in TS, ChaCha8Rng::seed_from_u64(seed) in Rust. A test fixes the seed; the game seeds from the clock or the save.MoveIntent(x, y), Jump), not key codes. Rebinding then never touches a rule.Naming follows the repository; without a convention: NUnit Method_Scenario_Expected, gdUnit4/GUT test_<scenario>_<expected>, Unreal Project.System.Scenario, Vitest/cargo test a sentence describing the behaviour.
One line per command in the closing message, verbatim:
NOT RUN: Unity 6000.3.2f1 not installed (Hub has 6000.0.40f1 only) — EditMode tests in Assets/Tests/EditMode/CooldownTests.cs written, not executed.
RAN: dotnet test /tmp/tt-T-42/core-tests → 12 passed, 0 failed (Core sources compiled without UnityEngine).
Random inside a rule, then fighting flaky tests.UnityEngine, Godot, Phaser or bevy::prelude without needing it.RAN:/NOT RUN: accounting on an engine project.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
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
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
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
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
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.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.