I cannot make Unity test-framework work with InputTestFixture

Hello! I’m currently doing some integration tests, and I’m failing to make my test run properly:

I’m on unity 2021.3.9f1, inputsystem: 1.4.2 and test-framework 2.0.1-exp.1

Here is the code:

using System.Collections;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;

namespace Tests
{
    [TestFixture]
    public class MovementComponentTest
    {
        private InputTestFixture _fixture = new InputTestFixture();
        private Keyboard _keyboard;

        private GameObject _sut;
        private Transform _transform;
        [UnitySetUp]
        public IEnumerator USetUp()
        {
            yield return SceneManager.LoadSceneAsync(
                "TestScene",
                new LoadSceneParameters(LoadSceneMode.Single, LocalPhysicsMode.Physics3D)
            );
        }

        [SetUp]
        public void SetUp()
        {
            _fixture.Setup();  
            _keyboard = InputSystem.AddDevice<Keyboard>();
           
            LoadTestPlayerPrefab();
        }
       
        [TearDown]
        public void TearDown()
        {
            _fixture.TearDown();  
        }

        [UnityTearDown]
        public void UTearDown()
        {
            Debug.Log("Tearing dow");
        }

        [UnityTest]
        public IEnumerator ShouldNotMoveWhenNothingIsPressed()
        {
            yield return new WaitForFixedUpdate();

            AssertPositionRotation(
                new Vector3(0, 0, 0),
                Quaternion.Euler(0, 0, 0)
            );
        }

        [UnityTest]
        public IEnumerator ShouldMoveForwardWhenTheCorrespondingInputIsPressed()
        {
            _fixture.Press(_keyboard.wKey);
            yield return new WaitForFixedUpdate();
            _fixture.Release(_keyboard.wKey);
           
            AssertPositionRotation(
                new Vector3(0, 0, Time.fixedDeltaTime),
                Quaternion.Euler(0, 0, 0)
            );
        }

        [UnityTest]
        public IEnumerator ShouldMoveBackwardsWhenTheCorrespondingInputIsPressed()
        {
            _fixture.Press(_keyboard.sKey);
            yield return new WaitForFixedUpdate();
            _fixture.Release(_keyboard.sKey);
           
            AssertPositionRotation(
                new Vector3(0, 0, -Time.fixedDeltaTime),
                Quaternion.Euler(0, 0, 0)
            );
        }
       
        private void AssertPositionRotation(
            in Vector3 position,
            in Quaternion rotation
        )
        {
            Assert.That(_transform.position, Is.EqualTo(position));
            Assert.That(_transform.rotation, Is.EqualTo(rotation));
        }

        private void LoadTestPlayerPrefab()
        {
            var prefab = AssetDatabase.LoadAssetAtPath(
                "Assets/Tests/TestPrefabs/TestPlayer.prefab",
                typeof(GameObject)
            );

            _sut = Object.Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
            _transform = _sut.GetComponent<Transform>();
        }
    }
}

And here is the output I’m getting:

ShouldMoveForwardWhenTheCorrespondingInputIsPressed (0.501s)
---
SetUp : Unhandled log message: '[Exception] ArgumentOutOfRangeException: Cannot be negative
Parameter name: value'. Use UnityEngine.TestTools.LogAssert.Expect
---
UnityEngine.InputSystem.Users.InputUser.set_listenForUnpairedDeviceActivity (System.Int32 value) (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/Users/InputUser.cs:406)
UnityEngine.InputSystem.PlayerInput.StopListeningForUnpairedDeviceActivity () (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/PlayerInput/PlayerInput.cs:1685)
UnityEngine.InputSystem.PlayerInput.OnDisable () (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/PlayerInput/PlayerInput.cs:1720)
---
ArgumentOutOfRangeException: Cannot be negative
Parameter name: value
UnityEngine.InputSystem.Users.InputUser.set_listenForUnpairedDeviceActivity (System.Int32 value) (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/Users/InputUser.cs:406)
UnityEngine.InputSystem.PlayerInput.StopListeningForUnpairedDeviceActivity () (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/PlayerInput/PlayerInput.cs:1685)
UnityEngine.InputSystem.PlayerInput.OnDisable () (at Library/PackageCache/com.unity.inputsystem@1.4.2/InputSystem/Plugins/PlayerInput/PlayerInput.cs:1720)

Has anyone had the same issue? Am I doing something wrong with the Test-framework or the input system API? Thx in advance !

I had a similar issue which caused the same error message.

My solution was to destroy the GameObject which contains the PlayerInput before InputTestFixture TearDown.

So in your case, you would need to either unload the scene (note that TearDown is executed before UnityTearDown) or destroy _sut (depending on what contains PlayerInput components) before calling _fixture.TearDown()

Hi, did you ever find a solution to this issue? I’m experiencing the same exact problem.

I’ve tried destroying the PlayerInput gameObject as well as loading an empty scene in TearDown, but nothing seems to work. Does anyone know if there’s a simple working example of a test that uses the PlayerInput component in the loaded scene?

Thanks in advance.