Skip to main content

Write your first automated test for your own behaviour

How to write a real Play Mode test against your own TsvrcBehaviour subclass with Udon Test Kit, once your test assemblies are set up.

Steps​

  1. Extend the kit's ClientSimTestBase, give the class a scene of its own, and start ClientSim in a [UnityTest]:

    public class RoundRefereeTests : ClientSimTestBase
    {
    public RoundRefereeTests() : base(TestScene.Empty("RoundRefereeTests"))
    {
    }

    [UnityTest]
    public IEnumerator BeginRound_Owner_StartsTheRound()
    {
    yield return Session.Start();

    Every test gets a fresh empty scene, and everything it creates goes when the scene unloads.

  2. Add the behaviour under test to a GameObject and construct it, as your generated root does at world startup:

    var referee = new GameObject("RoundReferee").AddComponent<RoundReferee>();
    referee.TsConstruct((TsRoot)null);

    Pass null when the behaviour doesn't reach _ts during the test.

  3. Drive the behaviour and assert on it:

    referee.BeginRound();

    Assert.IsTrue(referee.IsProcessRunning());
    }
    }

Reaching a private field or method​

Use PrivateFieldAccess from Udon Test Kit instead of making something public just so a test can see it:

int remaining = PrivateFieldAccess.GetField<int>(referee, "_remainingMilliseconds");

Asserting an event actually fired​

Subscribe a spy from the Udon Test Kit CallLog instead of writing a one-off listener class for every test:

using var calls = new CallLog();
CallbackSpy listener = calls.CreateSpy("Listener");
referee.TsSubscribe(listener, RoundReferee.OnRoundEndedEvent, nameof(CallbackSpy.CallbackA));

// ...drive the round to completion...

Assert.That(calls, Is.EqualTo(new[] { "Listener.CallbackA" }));

The log records each call in order, so the same assertion also fails if the event fired twice.

Testing as a player who isn't the owner​

A Process such as RoundReferee acts only for its owner and forwards everything else. Hand it to a remote player with the kit's Session.SetOwner to test the other side, as in Test what happens for a player who isn't the owner.

Why this shape​

See Testing your world for how a test builds your behaviours and what the Core codegen does during a test run.