Learn how to leverage Object References to simplify test definitions and improve performance
As of the 2025.01 release, you can now create object references through the API, and use those references as long as the object is valid in the application under test. This is useful in reducing the number of requests to the application using HPath queries, as well as in speeding up test execution. This approach differs from the EnableObjectCaching command which is an "all-or-nothing" approach, which can lead to stale object or property references in more dynamic scenes. Using CreateObjectRef allows you to cache individual object references, optionally including specific components or properties.
There are two API methods for working with Object References:
The CreateObjectRef method had 3 overloads, the first of which will cover most testing use cases. The method takes the HPath of an existing object and returns a reference to that object which can be used on the client side to streamline test creation and maintenance.
public ObjectRef CreateObjectRef(string hpath, int timeout = 30)
The ObjectRef here is the resolved object, meaning you only need to query the HPath once in your test, and then use the reference to continue working with the object. How this differs from the traditional approach can be demonstrated as follows:
Traditional approach:
//Get the position of a UI object containing a slider
var sliderPos = api.GetObjectPosition("//*[@name='ActiveSlider']";
//Get the initial value of the slider
var sliderVal = api.GetObjectFieldValue<float>($"//*[@name='ActiveSlider']/fn:component('UnityEngine.UI.Slider')/@value");
//Drag the mouse to change the slider value
api.MouseDrag(MouseButtons.LEFT, new Vector2(sliderPos.x + 50, sliderPos.y), 60, new Vector2(sliderPos.x, sliderPos.y), true);
//Get the new value of the slider
var sliderValAfter = api.GetObjectFieldValue<float>($"//*[@name='ActiveSlider']/fn:component('UnityEngine.UI.Slider')/@value");
//Check that the value has changed
Assert.That(sliderValAfter > sliderVal);
Object Reference approach:
var sliderRef = api.CreateObjectRef("//*[@name='ActiveSlider'])");
//Get the position of a UI object containing a slider
var sliderPos = api.GetObjectPosition($"fn:objectref('{sliderRef}')";
//Get the initial value of the slider
var sliderVal = api.GetObjectFieldValue<float>($"fn:objectref('{sliderRef}')/fn:component('UnityEngine.UI.Slider')/@value");
//Drag the mouse to change the slider value
api.MouseDrag(MouseButtons.LEFT, new Vector2(sliderPos.x + 50, sliderPos.y), 60, new Vector2(sliderPos.x, sliderPos.y), true);
//Get the new value of the slider
var sliderValAfter = api.GetObjectFieldValue<float>($"fn:objectref('{sliderRef}')/fn:component('UnityEngine.UI.Slider')/@value");
//Check that the value has changed
Assert.That(sliderValAfter > sliderVal);
While these examples might appear similar, and the "Object Reference" approach even has an additional line of code, there is a key difference in the number of HPath queries performed by the GDIOAgent in each.
In the first example, we are performing 3 separate HPath queries during test execution, whereas in the second example, we are only performing 1 - the CreateObjectRef command. All subsequent calls to that reference are cached by the Agent and therefore will execute much more quickly.
While HPath queries are generally very fast (i.e. <100ms in most tested cases), this approach can dramatically speed up test execution when thousands of such queries are made during a test by cutting down the number of repetitive queries executed to resolve the same set of objects.
Note: As a best practice, be sure to destroy any object references using RemoveObjectRef when scene changes or expected object changes will invalidate the reference.