Claude Code Plugins

Community-maintained marketplace

Feedback

This skill should be used when the user asks about "tests", "unit tests", "EditMode tests", "PlayMode tests", "Test Runner", "test coverage", "NUnit", "Assert", "test fixtures", "writing tests", "running tests", or discusses Unity testing patterns and practices.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name unity-testing
description This skill should be used when the user asks about "tests", "unit tests", "EditMode tests", "PlayMode tests", "Test Runner", "test coverage", "NUnit", "Assert", "test fixtures", "writing tests", "running tests", or discusses Unity testing patterns and practices.
version 0.2.0

Unity Testing

Expert knowledge of Unity testing patterns, EditMode/PlayMode tests, and test-driven development for the Zero-Day Attack project.

Test Types

EditMode Tests

Run without entering Play mode - fast iteration:

Property Value
Location Assets/Tests/Editor/
Assembly *.Tests.Editor.asmdef
Speed Fast (no scene loading)
Use For Pure logic, data validation, calculations

PlayMode Tests

Run in simulated Play mode - test runtime behavior:

Property Value
Location Assets/Tests/Runtime/
Assembly *.Tests.Runtime.asmdef
Speed Slower (scene setup required)
Use For MonoBehaviour, scene interactions, integration

Project Test Structure

Assets/Tests/
├── Editor/
│   ├── BoardLayoutConfigTests.cs    # LayoutConfig validation
│   └── TileDatabaseTests.cs         # Database integrity
└── Runtime/
    ├── CoordinateConversionTests.cs # Grid-to-world conversion
    └── GameInitializationTests.cs   # Startup and state

Writing EditMode Tests

EditMode Test Basic Structure

using NUnit.Framework;
using ZeroDayAttack.Config;

namespace ZeroDayAttack.Tests.Editor
{
    [TestFixture]
    public class LayoutConfigTests
    {
        [Test]
        public void GridSize_ShouldBeFive()
        {
            Assert.AreEqual(5, LayoutConfig.GridSize);
        }

        [Test]
        public void ScreenDimensions_ShouldMatch1920x1080()
        {
            // At 100 PPU: 1920/100 = 19.2, 1080/100 = 10.8
            Assert.AreEqual(19.2f, LayoutConfig.ScreenWidth, 0.001f);
            Assert.AreEqual(10.8f, LayoutConfig.ScreenHeight, 0.001f);
        }

        [Test]
        public void CameraOrthoSize_ShouldBeHalfHeight()
        {
            float expectedOrtho = LayoutConfig.ScreenHeight / 2f;
            Assert.AreEqual(expectedOrtho, LayoutConfig.CameraOrthoSize, 0.001f);
        }
    }
}

Testing ScriptableObjects

using NUnit.Framework;
using UnityEngine;
using ZeroDayAttack.Core.Data;

namespace ZeroDayAttack.Tests.Editor
{
    [TestFixture]
    public class TileDatabaseTests
    {
        private TileDatabase database;

        [OneTimeSetUp]
        public void LoadDatabase()
        {
            database = Resources.Load<TileDatabase>("TileDatabase");
        }

        [Test]
        public void Database_ShouldLoad()
        {
            Assert.IsNotNull(database, "TileDatabase not found in Resources");
        }

        [Test]
        public void Database_ShouldHave25Tiles()
        {
            Assert.AreEqual(25, database.Tiles.Count);
        }

        [Test]
        public void AllTiles_ShouldHaveSprites()
        {
            foreach (var tile in database.Tiles)
            {
                Assert.IsNotNull(tile.TileSprite,
                    $"Tile {tile.TileId} missing sprite");
            }
        }
    }
}

Writing PlayMode Tests

PlayMode Test Basic Structure

using System.Collections;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using ZeroDayAttack.View;

namespace ZeroDayAttack.Tests.Runtime
{
    [TestFixture]
    public class TileManagerTests
    {
        private TileManager tileManager;

        [UnitySetUp]
        public IEnumerator SetUp()
        {
            // Create test object
            var go = new GameObject("TileManager");
            tileManager = go.AddComponent<TileManager>();
            yield return null;  // Wait one frame
        }

        [UnityTearDown]
        public IEnumerator TearDown()
        {
            if (tileManager != null)
            {
                Object.Destroy(tileManager.gameObject);
            }
            yield return null;
        }

        [UnityTest]
        public IEnumerator Instance_ShouldBeSet()
        {
            yield return null;
            Assert.IsNotNull(TileManager.Instance);
        }

        [UnityTest]
        public IEnumerator GridToWorld_CenterTile_ShouldBeAtOrigin()
        {
            yield return null;
            var worldPos = tileManager.GetWorldPosition(2, 2);
            Assert.AreEqual(0f, worldPos.x, 0.001f);
            Assert.AreEqual(0f, worldPos.y, 0.001f);
        }
    }
}

Testing with Scenes

using UnityEngine.SceneManagement;

[UnityTest]
public IEnumerator GameplayScene_ShouldLoad()
{
    SceneManager.LoadScene("GameplayScene");
    yield return null;  // Wait for load

    var gameManager = GameObject.FindObjectOfType<GameManager>();
    Assert.IsNotNull(gameManager);
}

Common Assertions

Value Assertions

Assert.AreEqual(expected, actual);
Assert.AreEqual(expected, actual, delta);  // For floats
Assert.AreNotEqual(notExpected, actual);
Assert.IsTrue(condition);
Assert.IsFalse(condition);

Null Assertions

Assert.IsNull(obj);
Assert.IsNotNull(obj);

Collection Assertions

Assert.Contains(item, collection);
Assert.IsEmpty(collection);
Assert.IsNotEmpty(collection);
CollectionAssert.AreEqual(expected, actual);
CollectionAssert.AreEquivalent(expected, actual);  // Order-independent

Exception Assertions

Assert.Throws<ArgumentException>(() => {
    SomeMethod(invalidArg);
});

Assert.DoesNotThrow(() => {
    SomeMethod(validArg);
});

Running Tests via MCP

Run All EditMode Tests

{
  "testMode": "EditMode"
}

Run Specific Test Class

{
  "testMode": "EditMode",
  "testClass": "LayoutConfigTests"
}

Run Specific Test Method

{
  "testMode": "EditMode",
  "testMethod": "ZeroDayAttack.Tests.Editor.LayoutConfigTests.GridSize_ShouldBeFive"
}

Useful Options

{
  "testMode": "EditMode",
  "includePassingTests": false, // Only show failures
  "includeMessages": true, // Include assertion messages
  "includeStacktrace": true, // Include stack traces
  "includeLogs": true // Include console logs
}

Test Naming Conventions

Pattern: Method_Scenario_ExpectedResult

[Test] public void GridToWorld_CenterTile_ReturnsOrigin() { }
[Test] public void PlaceTile_InvalidPosition_ThrowsException() { }
[Test] public void MoveToken_ValidPath_UpdatesPosition() { }

Test Class Naming

public class GameManagerTests { }      // Tests for GameManager
public class TileValidationTests { }   // Tests for tile validation logic
public class PathFindingTests { }      // Tests for path algorithms

Test Categories

Organize tests with categories:

[Test]
[Category("FastTests")]
public void QuickCalculation_Test() { }

[Test]
[Category("Integration")]
public void SceneSetup_Test() { }

Run by category:

{
  "testMode": "EditMode",
  "testCategory": "FastTests"
}

Testing Best Practices

Arrange-Act-Assert Pattern

[Test]
public void PathSegment_RotateBy90_UpdatesNodes()
{
    // Arrange
    var segment = new PathSegment(EdgeNode.Left, EdgeNode.Top, PathColor.Blue);

    // Act
    var rotated = segment.Rotate(90);

    // Assert
    Assert.AreEqual(EdgeNode.Top, rotated.From);
    Assert.AreEqual(EdgeNode.Right, rotated.To);
}

One Assertion Per Test (When Practical)

// Good: Focused tests
[Test] public void Tile_HasCorrectWidth() { }
[Test] public void Tile_HasCorrectHeight() { }

// OK for related properties
[Test]
public void Tile_HasCorrectDimensions()
{
    Assert.AreEqual(2.0f, tile.Width);
    Assert.AreEqual(2.0f, tile.Height);
}

Test Independence

Each test should be independent:

  • Use [SetUp] for common initialization
  • Use [TearDown] for cleanup
  • Don't rely on test execution order

Fast Tests

Prefer EditMode tests when possible:

  • No scene loading overhead
  • Pure logic tests run instantly
  • Use PlayMode only when necessary

Existing Tests

BoardLayoutConfigTests

Tests LayoutConfig constants:

  • Grid dimensions
  • Screen dimensions
  • Camera settings
  • Zone coordinates

TileDatabaseTests

Tests TileDatabase integrity:

  • Database loads from Resources
  • Correct tile count (25)
  • All tiles have sprites
  • All tiles have valid path data

CoordinateConversionTests

Tests TileManager coordinate conversion:

  • Grid-to-world mapping
  • Center tile at origin
  • Corner positions correct

GameInitializationTests

Tests game startup:

  • Managers initialize correctly
  • Scene hierarchy valid
  • Initial state correct

Additional Resources

Reference Files

For test examples:

  • Assets/Tests/Editor/ - EditMode test examples
  • Assets/Tests/Runtime/ - PlayMode test examples

Running Tests in Unity

Window > General > Test Runner

  • EditMode tab for editor tests
  • PlayMode tab for runtime tests