1
\$\begingroup\$

I'm experiencing an issue with my PlayMode tests, where all tests pass individually, but when running 21 or more tests together (using Run Selected or Run All), the same 2 tests fail. From further investigation, it appears that the MonoBehaviour lifecycle events aren't firing when running all of the tests - when I run the tests individually, they fire as expected.

Failing Tests

failing tests

Tests passing when run individually

tests passing

These two tests are the only ones that depend on the OnEnable() lifecycle event being triggered. Here is the first test, GivenCursorHasState_WhenEnabled_ThenTheCursorPositionShouldBeRestoredFromState()

[UnityTest]
public IEnumerator GivenCursorHasState_WhenEnabled_ThenTheCursorPositionShouldBeRestoredFromState()
{
    // Disable the component, expect OnDisable() to fire
    selection.enabled = false;
    yield return null;

    var state = new CursorState { cursorPosition = 5 };
    StateCache.Store(cursor, state);

    // Enable the component, expect OnEnable() to fire
    selection.enabled = true;
    yield return null;

    var expectedItem = menuItems[5];
    var actualItem = selection.GetCurrentItem();

    // The next line is where the failure is triggered
    Assert.AreEqual(expectedItem, actualItem);
    Assert.AreEqual(expectedItem.transform.position.y, cursor.transform.position.y);
    Assert.AreNotEqual(expectedItem.transform.position.x, cursor.transform.position.x);
    Assert.AreEqual(originalCursorPositionX, cursor.transform.position.x);
}

This is the components, OnEnable() method:

void OnEnable()
{
    var state = StateCache.Get<CursorState>(gameObject);

    if (state == null)
    {
        SelectFirstEnabledItem();
    }
    else
    {
        // We might be retaining a position already in state
        cursorPosition = state.cursorPosition;

        UpdateCursorPosition();
    }
}

I'm setting up the test with the following method:

[SetUp]
public void Setup()
{
    var prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefabs/UI/Menu.prefab");
    var menu = GameObject.Instantiate<GameObject>(prefab);
    selection = menu.GetComponentInChildren<MenuItemSelection>();

    menuItems = selection.menuItems;
    cursor = selection.gameObject;
    originalCursorPositionX = cursor.transform.position.x;
}

I've checked the StateCache between steps, and that appears to be working as expected - as in there is no pollution between tests with it being a static class.

I'm hoping I'm just misunderstanding something about how the tests and/or lifecycle events work here. Any guidance is appreciated!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Can you test whether it's really the sheer quantity of tests, and not something specific in the contents of the other tests? Try making a new project, and fill it up with 20+ tests that all just immediately succeed, plus one of the tests that's currently misbehaving. If it fails there too, that sounds like a Unity bug. If it works there, then it sounds like an interaction between the contents of some of your tests. \$\endgroup\$
    – DMGregory
    Commented Apr 11, 2023 at 11:12
  • \$\begingroup\$ @DMGregory I'm having trouble setting up an isolated reproduction of this issue, so I either don't understand it enough, or I'm missing something specific to my project. This is the repro project I have started adding to: github.com/sladesamuel/unity-lifecycle-tests \$\endgroup\$ Commented Apr 11, 2023 at 13:44

1 Answer 1

1
\$\begingroup\$

In the end, I reworked this solution. Instead of using a static StateCache instance with static data that was clearly bleeding through my tests when run in batch, I made use of dependency injection. The framework I used for this was Zenject.

In my game code, I now setup my StateCache as a singleton dependency, but within the context of my tests, I change this to a transient instance. This allows my tests to be completely isolated, and therefore no state bleeding occurs between tests.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .