Skip to content

Creating Functional Tests with the Automation System

In this post I’m going to show you how to create Functional Tests with the Automation System that comes with the latest version of Unreal Engine 4. With functional tests, we can simulate a user’s behavior (to some extent) and verify that everything is working properly.

In this post we’re going to create a simple script that tests if the player can move X units forward to a level. Once you become familiar with the process you will be able to extend the testing functionality to interactions or more complex systems of your game.

Implementing a functional test

Fortunately, Unreal provides a straightforward to jump start our functional tests. For this post, I’m using a C++ Third Person Template project. To create a functional test, add a new C++ class that inherits the FunctionalTest class. In your header file, add the following code:

#include "CoreMinimal.h"
#include "FunctionalTest.h"
#include "PlayerMovementFunctionalTest.generated.h"

/**
 * A functional test that moves the player character forward
 */
UCLASS()
class AUTOMATIONPOST_API APlayerMovementFunctionalTest : public AFunctionalTest
{
	GENERATED_BODY()

private:

	/* Reference of main player */
	class ACharacter* Player;

	/* Initial location of the player */
	FVector InitialLocation;

protected:

	virtual void BeginPlay() override;

	/* Total movement distance */
	UPROPERTY(EditAnywhere)
	float MovementDistance = 250.f;

	/* Distance threshold in order to get for target location */
	UPROPERTY(EditAnywhere)
	float DistanceThreshold=55.f;

public:

	virtual void Tick(float DeltaSeconds) override;

	/**
	 * Returns true when the player has traveled MovementDistance - DistanceThreshold
	 */
	bool TraveledTotalDistance() const;
	
};

On the source file, add the following code:

#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"

void APlayerMovementFunctionalTest::BeginPlay()
{
	Super::BeginPlay();


	Player = UGameplayStatics::GetPlayerCharacter(GetWorld(),0);

	if (Player)
	{
		InitialLocation = Player->GetActorLocation();
	}
}

void APlayerMovementFunctionalTest::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	if (Player)
	{
		//Go forward until we reach our destination
		Player->AddMovementInput(Player->GetActorForwardVector());
		if (TraveledTotalDistance())
		{
			FinishTest(EFunctionalTestResult::Succeeded,FString("Traveled required units!"));
			UKismetSystemLibrary::QuitGame(GetWorld(),UGameplayStatics::GetPlayerController(GetWorld(),0),EQuitPreference::Quit,false);
		}
	}
	else
	{
		FinishTest(EFunctionalTestResult::Failed, FString("Invalid player character!"));
	}
}

bool APlayerMovementFunctionalTest::TraveledTotalDistance() const
{
	return (Player) ? (FVector::Distance(Player->GetActorLocation(), InitialLocation + Player->GetActorForwardVector() * MovementDistance) <= DistanceThreshold) : false;
}

Compile your code and navigate to your Editor and locate your C++ class. If the C++ Classes folder isn’t visible, make sure to Activate the Show C++ filter from the editor

(Click on image to enlarge)

Once you locate your C++ class, just drag and drop it into your level:

(Click on image to enlarge)

At this point, open up the Session FrontEnd window and notice that in the Automation Tab a new test was added under the Project Category:

(Click on image to enlarge)

In order to run your test you can either:

  • Enable its checkbox and press the Start Tests or
  • Press the Run Level Test. The editor has already marked this level as a test once you placed a functional test in the world
Functional Test

And this is how you can create a simple functional test for your game! Thanks for reading and have a nice day!

Avatar photo

Comments (0)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back To Top