Learn how to use GameDriver together with the Unreal Automated Testing framework
With GameDriver’s new integration with Unreal’s Automation Testing Framework, you can now leverage the power of Gamedriver inside of Unreal, including through Blueprints! A complete list of the GameDriver API for C++/Blueprints is available on GitHub. We also have a guide to using GameDriver tools in Unreal Engine.
Prerequisites
Navigate to Edit -> Plugins and enable the Functional Testing Editor plugin.
Unreal Engine will restart to enable the plugin.
Testing with Blueprints
With the GameDiver plugin installed and the license active you will have access to the GameDriver API. To demonstrate we will create a new blueprint class inherited from a FunctionalTest. When you place the Actor in the game you will be able to run it from the automation UI.
To access the GameDriver Blueprints inside the Functional Test simply right-click and start typing GameDriver to see a complete list of functions available to you. Alternatively, start typing the name of a known API method to get access to it.
To illustrate a simple test consider the blueprint below. It executes when the test starts. As you can see it uses GetObjectList to retrieve a list of Objects matching an HPath string (more on that in a moment), and then checks the length to see if it’s one, passing the test if it is, and failing if it isn’t.
Simulating a Keypress in Blueprints
Here we see a “W” key being simulated for 30 frames.
Resolving an Object using HierarchyPath in Blueprints
Hierarchy Path is a robust query language that enables you to identify any object, component, or property in a scene based on one or more characteristics of that object. GetGameObject resolves one singular object, while GetObjectList can retrieve a matching TArray of UObject* which you can cast and use accordingly. Hpath is a powerful language with many such query options available to you. A more complete look at what kinds of queries you can write is available here.
Here we see a query to get an object by name, which is then cast to a known Class for further manipulation.
In the next example, we use //*[@class='BP_EnergyOrb_C' and @tag='Active'] as an HPath value, which gets all the objects of class BP_EnergyOrb_C, but only if they also have a tag value of Active.
Simulating a Click in Blueprints with GameDriver
Up until now, it was difficult to simulate a mouse click through blueprints. With GameDriver functions such as MoveMouse, Click, ClickObject, KeyPress, and InputFloat, you can simulate all kinds of user input with easy-to-understand blueprint nodes.
The example below shows a MouseMoveToObjectFromHPath, ClickObjectFromHPath, and then the use of getGameObject to inspect the visibility of a Slate button (which in this game should have been hidden by the click).
For a complete list of methods available to you check out our GitHub documentation on Unreal gameDriver Blueprints.
Testing with C++
Using Unreal’s automated testing you can create unit or feature tests. By adding the Gamedriver header to your project you get access to a subset of the complete API, specially tailored for use within Unreal Engine.
Whether you’re running your tests through the front-end GUI or the command line, you are likely using the IMPLEMENT_SIMPLE_AUTOMATION_TEST macro (or the complex version) to create a test that will appear in the editor.
To start with a quick example, let’s use a GameDriver API call to get a list of objects matching a HierarchyPath and then make sure that list is 1 long. For this, we’ll use GetObjectList:
#include "CoreTypes.h"
#include "Misc/AutomationTest.h"
#include <GameDriver/Public/GDIOApiLibrary.h>
IMPLEMENT_SIMPLE_AUTOMATION_TEST(UMyTest1, "GameDriver test", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
bool UMyTest1::RunTest(const FString& Parameters)
{
TArray<UObject*> objects = UGDIOApi::GetObjectList("//ThirdPersonCharacter_167");
if (objects.Num() == 1)
{ return true; }
return false;
}
Listing 1: A simple test with GameDriver to GetObjectList.
Simulating a Keypress in C++
A common desire in testing is to simulate Key input, either from a keyboard or gamepad.
With raw Unreal testing, you can add a keypress by passing in an Array of FKeys (often only one).
TArray<FKey>F;
F.Add(EKeys::F);
UGDIOApi::KeyPress(F, 1);//press F for one frame.
Resolving an Object using HierarchyPath in C++
One of the easiest things to do in the API is also one of the most powerful. Hierarchy Path is a robust query language that enables you to identify any object, component, or property in a scene based on one or more characteristics of that object. GetGameObject resolves one singular object, while GetObjectList can retrieve a matching TArray of UObject* which you can cast and use accordingly.
// Get one object
UObject* robot1 = UGDIOApi::GetGameObject("/*[@name = 'BP_Shrub_C_0']");
// Get Many objects
TArray<UObject*> objects = UGDIOApi::GetObjectList("//*[@class='BP_Shrub_C']");
For a complete listing of HierarchyPath usage see the usage guide here.
Simulating a Click in C++ with GameDriver
When simulating mouse and keyboard events there may be a need to delay input. In Gamedriver’s C# API, you can simply call Wait() and then proceed. In Blueprints, you use the Delay node (which is only available in the main event Graph of your actors). In Unreal’s test framework, you create latent methods out of each part of your test and then call them in order. In many ways, this mimics the blueprint nodes.
For example, you may want to write the following conceptual test:
UGDIOApi::MouseMovetoObject("/simpleButton_C_0/Button", 30);
UGDIOApi.Wait(3000);
UGDIOApi::ClickObject(EKeys::LeftMouseButton, "/simpleButton_C_0/Button", 30);
UGDIOApi.Wait(1000);
CheckVisibility(); //cast to UWidget and check Visibility.
To do this, you need to break it into latent commands that you can then call in sequence like this:
IMPLEMENT_SIMPLE_AUTOMATION_TEST(GameDriverMouseMoveAndClick, "GameDriverMouseMoveAndClick", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
bool GameDriverMouseMoveAndClick::RunTest(const FString& Parameters)
{
bool worked = false;
UGDIOApi::MouseMovetoObject("/simpleButton_C_0/Button", 30);
ADD_LATENT_AUTOMATION_COMMAND(FWaitLatentCommand(3));
ADD_LATENT_AUTOMATION_COMMAND(Click());
ADD_LATENT_AUTOMATION_COMMAND(FWaitLatentCommand(1));
ADD_LATENT_AUTOMATION_COMMAND(CheckVisibility());
return true;
}
DEFINE_LATENT_AUTOMATION_COMMAND(Click);
bool Click::Update()
{
UGDIOApi::ClickObject(EKeys::LeftMouseButton, "/simpleButton_C_0/Button", 30);
return true;
}
DEFINE_LATENT_AUTOMATION_COMMAND(CheckVisibility);
bool CheckVisibility::Update()
{
UObject* widgetObj = UGDIOApi::GetGameObject("/simpleButton_C_0/Button");
if (widgetObj == NULL) return false;
if (widgetObj->IsA<UWidget>()) {
UWidget* widge = (UWidget*)widgetObj;
if (widge->GetVisibility()== ESlateVisibility::Hidden)
return true;
}
return false;
}
Running Tests
The Test Automation UI can be accessed by navigating to Tools -> Test Automation as seen in the image below. This is where the tests are run.