XRPractices
Published in

XRPractices

Arium — An Automation framework for Unity/XR

Arium is a lightweight, extensible, platform-agnostic framework for writing automation tests in Unity not limited to but built specifically for XR Applications.

The Arium project can be found at
https://github.com/thoughtworks/Arium

Instructions on how to setup Arium can be found in the above link.

So this article will cover the setting up of Arium for a VR Project (learn more about how the VR project was set up). The reference project can be found here

The Arium integration is demonstrated on the Branch arium-integration.

Testing movement and collecting crystals

What are we testing?

We are testing a Virtual Reality Game, in which the player can move around the map and collect crystals.

So there are 2 primary interactions in this game

  1. The Player moving in 3D space
  2. Collecting the Crystals

How can we test it?

For the article’s purpose, we will be covering automation testing.
Let’s start with the test cases...

1. The player should be able to move around the 3D space by tapping on the surface.

So first we need to Load the Scene and initialize Arium, we will use the default constructor of Arium for the same.

private Arium _arium;[OneTimeSetUp]
public void OneTimeSetUp()
{
_arium = new Arium();
SceneManager.LoadScene("Main");
}

Once an Arium instance is created we will be able to interact with all the objects in the loaded scene. For our case, we will be interacting with the ground and try to click at a certain point.

[UnityTest]
public IEnumerator ShouldMoveToPosition()
{
Vector3 position = new Vector3(3f, 0.1f, 6f);
PointerEventData eventData =
new PointerEventData(EventSystem.current)
{ pointerPressRaycast = new RaycastResult
{
worldPosition = position
}
};

_arium.PerformAction(
new UnityPointerClick(eventData), "Ground");
...

Here we are creating a Click action at a certain point on the “Ground” (name of the GameObject). For this we create new UnityPointerClick interaction and pass a custom made PointerEventData that contains the position where the Player needs to tap.

Next, we need to wait for the action to complete and check whether the player has moved to a particular position.

...    yield return new WaitForSeconds(4);

float distance = Vector3.Distance(position,
_arium.GetComponent<Transform>("Player").position);

Assert.IsTrue(distance < 0.02f);
}

Here we use Arium’s GetComponent to get the Transform component of the “Player” (name of the GameObject).
And check if the “Player” has reached the destination (with 0.02 tolerance).

2. The Player should be able to collect the Crystals by tapping it.

So we start by moving the Player near one of the Crystals (“Collectable”) in a similar fashion as the above test.

[UnityTest]
public IEnumerator ShouldDestroyCollectableOnCollection()
{
const string collectable = "Collectable";
Transform player = _arium.GetComponent<Transform>("Player");
Transform collectableTransform =
_arium.GetComponent<Transform>(collectable);

Vector3 position = Vector3.Lerp(
player.position, collectableTransform.position, 0.5f);

PointerEventData eventData =
new PointerEventData(EventSystem.current)
{
pointerPressRaycast =
new RaycastResult {worldPosition = position}
};

_arium.PerformAction(
new UnityPointerClick(eventData), "Ground")
;

yield return new WaitForSeconds(2);

player.LookAt(collectableTransform);
...

Once the “Player” has reached close to the “Collectable”, and look at the “Collectable”.

...        Assert.IsTrue(
_arium.GetComponent<Animator>("Reticle").GetBool(IsOpen));

_arium.PerformAction(new UnityPointerClick(), collectable);

yield return new WaitForSeconds(2);

Assert.Throws<GameObjectNotFoundException>(
() => _arium.FindGameObject(collectable));
}
  • Firstly we need to check if the reticle opens up when. the “Player” looks at the “Collectable” from within a 10unit radius. We do this by getting the Animator Component of the “Reticle” GameObject using Arium and check if the animator parameter is open.
  • We perform a click using a similar Arium UnityPointerClick interaction, but this time we don’t specify any position and let Arium use a generic event data.
  • Finally, we wait for a moment and check if the “Collectable” is still present, by using Arium’s FindGameObject which throws a GameObjectNotFoundException when a GameObject is absent or destroyed.

Thus concluding our tests!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Neelarghya

Stuck between being the fly on the wall and the eye of the storm…