How to simulate Mouse movement for Automated Testing?

Hey

So I’m working on a research project looking into how to effectively use and work with automated testing in Unity, using the Test Framework, Performance Testing Package, etc.

However, I’m currently stuck on trying to simulate the movement of the mouse for moving the player character. I’m working in a VR project and simulating the VR headset during tests with the XR Device Simulator prefab from the XR Interaction Toolkit sample.
I have successfuly tested player movement, using the Device Simulator and using a virtual keyboard and giving it inputs through the InputSystem, so I am fairly sure my setup itsn’t wrong.

But it seems like InputSystem might not support movement of the mouse, altough I’m not sure.
Is there anybody who has done this before, or has any ideas of how one would do this?

I’m also open to other alternatives, as long as it can be done during tests.

Here is my current testing class

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

public class PlayDummyTest
{

    private static GameObject simulatorInstance;
    private static Keyboard virtualKeyboard;
    private static Mouse virtualMouse;

    [UnitySetUp]
    public IEnumerator Setup()
    {
        SetDevices(false);
        yield return null;

        SceneManager.LoadScene("DemoScene");
        yield return null;

        string simulatorPath = "Assets/Samples/XR Interaction Toolkit/3.1.1/XR Device Simulator/XRDeviceSimulator/XR Device Simulator.prefab";
        GameObject simulatorPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(simulatorPath);
        simulatorInstance = (GameObject)PrefabUtility.InstantiatePrefab(simulatorPrefab);
        Assert.IsNotNull(simulatorInstance);
        yield return null;

        virtualKeyboard = InputSystem.AddDevice<Keyboard>("Virtual Keyboard");
        virtualMouse = InputSystem.AddDevice<Mouse>("Virtual Mouse");
        yield return null;
    }

    [UnityTearDown]
    public IEnumerator Teardown()
    {
        InputSystem.RemoveDevice(virtualKeyboard);
        InputSystem.RemoveDevice(virtualMouse);
        SetDevices(true);
        yield return null;

        GameObject.DestroyImmediate(simulatorInstance);
        simulatorInstance = null;
        yield return null;
    }

    private void SetDevices(bool active)
    {
        foreach (InputDevice device in InputSystem.devices)
        {
            if (active)
                InputSystem.EnableDevice(device);
            else
                InputSystem.DisableDevice(device);
        }
    }

    [UnityTest]
    public IEnumerator MoveTest()
    {
        Transform target = Camera.main.transform;
        Vector3 startPos = target.position;
        Vector3 expectedForward = target.forward;

        InputSystem.QueueStateEvent(virtualKeyboard, new KeyboardState(Key.W));
        InputSystem.Update();
        yield return new WaitForSeconds(5);

        Vector3 endPos = target.position;
        Vector3 actualForward = (endPos - startPos).normalized;

        Assert.AreNotEqual(startPos, endPos);//Make sure we moved
        Assert.AreEqual(expectedForward, actualForward);//Make sure we moved in the expected direction
    }

    [UnityTest]
    public IEnumerator GrabTorusTest()
    {
        //Arrange
        GameObject torus = GameObject.Find("Interactable Kinematic Torus");
        Assert.IsNotNull(torus);

        GameObject origin = GameObject.Find("XR Origin (XR Rig)");
        Assert.IsNotNull(origin);

        Vector3 originNewPos = new Vector3(torus.transform.position.x - 0.5f, origin.transform.position.y, torus.transform.position.z);
        Vector3 originNewRot = new Vector3(0, origin.transform.rotation.eulerAngles.y - 90, 0);

        //Act
        origin.transform.position = originNewPos;
        origin.transform.rotation = Quaternion.Euler(originNewRot);

        Vector3 oldForward = origin.transform.forward;

        MouseState ms = new MouseState()
        {
            position = virtualMouse.position.ReadValue() + new Vector2(0, 50)
        };
        InputSystem.QueueStateEvent(virtualMouse, ms);
        InputSystem.Update();

        yield return new WaitForSeconds(3);

        Vector3 newForward = origin.transform.forward;
        Assert.AreNotEqual(oldForward, newForward, "Mouse didn't move.");
    }

}

My test MoveTest() succeeds, but GrabTorusTest() doesn’t because the mouse doesn’t move the simulated player camera as intended.

Any help would be appreciated!

What’s the purpose of testing player input?

For one, you can trust Unity’s systems to provide the input as needed. You can then simply concentrate on firing simulated input events. If you really, really want to test that the point of view is turning to the right when the mouse is moving to the right you just fire a series of mouse delta events with a Vector2(1, 0). That’s it!

Now your mouse or the headset could both provide that input. Leave that out of the equation. Simply test whether the camera rotates to the right when given a Vector2.right. This is what testing boils down to.

What you absolutely want to avoid testing is a series of gameplay situations. That’s not a unit test, that’s an integration test. And for the most part, that’s tests that you are doing all the time anyway. Put on your headset, look around, works? Good. No tests needed.

Especially things like input really, really don’t need any tests since you’re exercising that part of the code on a daily basis, running playtests.

What you really, really do want to test are the things that you absolutely have to trust never to provide incorrect results. A collection that “forgets” items or counts them incorrectly would be a disaster, and may not be immediately obvious. The player on the other hand not responding to a particular input event - dead obvious.

So focus your testing on where testing is best applied to. There’s a saying wide and far that you don’t test the UI. User Input is just that: UI. The literal User Interface.

I’m making tests for movement systems that I already know works, because the point of this isn’t to test them, but to figure out how to make the tests themselves.
If my tests fail, then it’s not because the systems I’m testing are faulty, but because my tests are. The purpose isn’t to test these packages, but rather to figure out how to write different kinds of tests in Unity, see?

This whole project is specifically to gain knowledge on how one would do all kinds of testing in Unity. I have already worked with unit tests, and now I’m focusing on how functional tests can be made.

If you’re unsure about the different types of testing, Unity made a nice article that summarise various testing and quality assurance techniques, including various types of automated testing: