Ue Testing Debugging
Use when writing automation tests, functional tests, or any test in Unreal Engine. Also use when the user asks about "UE_LOG", logging, log categories, assertion, check, ensure, verify, DrawDebug, debug draw, console command, profiling, Unreal Insights, stat commands, or debugging techniques. See ue-module-build-system for test module setup, and ue-cpp-foundations for general C++ logging patterns.
- Skill ID
- quodsoler/unreal-engine-skills/ue-testing-debugging
- Publisher
- quodsoler
- Repository
- unreal-engine-skills
- Installs
- 0
- Files
- 3
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
quodsoler/unreal-engine-skills/ue-testing-debuggingInstalls these files- SKILL.md
- references/automation-test-patterns.md
- references/profiling-commands.md
What this skill tells the agent
UE Testing & Debugging
You are an expert in testing, debugging, and profiling Unreal Engine C++ projects.
Context
Read .agents/ue-project-context.md for engine version, existing log categories, test infrastructure (automation modules, test maps), and project-specific conventions before providing guidance.
Before You Start
Ask which area the user needs help with if unclear:
- Automation tests — unit/integration tests using IMPLEMENT_SIMPLE_AUTOMATION_TEST
- Functional tests — actor-based AFunctionalTest in maps
- Logging — UE_LOG, custom categories, verbosity filtering
- Assertions — check, ensure, verify and when to use each
- Debug drawing — DrawDebug helpers for runtime visualization
- Console commands — UFUNCTION(Exec), FAutoConsoleCommand, CVars
- Profiling — Unreal Insights, stat commands, SCOPE_CYCLE_COUNTER
Automation Framework
Automation tests live in a dedicated module (e.g., MyGameTests) that depends on "AutomationController". Include the module in the editor target via ExtraModuleNames and conditionally in the game target via if (bWithAutomationTests).
Simple Tests
// Source/MyGameTests/Private/MyFeature.spec.cpp
#include "Misc/AutomationTest.h"
// Must specify one application context flag AND exactly one filter flag
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMyInventoryTest, "MyGame.Inventory.AddItem",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter)
bool FMyInventoryTest::RunTest(const FString& Parameters)
{
UInventoryComponent* Inv = NewObject<UInventoryComponent>();
Inv->AddItem(FName("Sword"), 1);
TestEqual(TEXT("Item count after add"), Inv->GetItemCount(FName("Sword")), 1);
TestTrue(TEXT("Has sword"), Inv->HasItem(FName("Sword")));
TestFalse(TEXT("No axe"), Inv->HasItem(FName("Axe")));
TestNotNull(TEXT("Inv valid"), Inv);
return true;
}Complex / Parameterized Tests
IMPLEMENT_COMPLEX_AUTOMATION_TEST requires overriding GetTests() to populate the parameter list, and RunTest(Parameters) receives each entry in turn.
IMPLEMENT_COMPLEX_AUTOMATION_TEST(FMyAssetLoadTest, "MyGame.Assets.LoadByPath",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter)
void FMyAssetLoadTest::GetTests(TArray<FString>& OutBeautifiedNames,
TArray<FString>& OutTestCommands) const
{
OutBeautifiedNames.Add(TEXT("Sword")); OutTestCommands.Add(TEXT("/Game/Items/BP_Sword"));
OutBeautifiedNames.Add(TEXT("Shield")); OutTestCommands.Add(TEXT("/Game/Items/BP_Shield"));
}
bool FMyAssetLoadTest::RunTest(const FString& Parameters)
{
UObject* Asset = StaticLoadObject(UObject::StaticClass(), nullptr, *Parameters);
if (!TestNotNull(TEXT("Asset loaded"), Asset)) { return false; }
TestTrue(TEXT("Is DataAsset"), Asset->IsA<UPrimaryDataAsset>());
return true;
}Test Assertion Methods
// Equality — overloaded for int32, int64, float, double, FVector, FRotator,
// FTransform, FColor, FLinearColor, FString, FStringView, FText, FName
TestEqual(TEXT("Label"), Actual, Expected);
TestEqual(TEXT("Float approx"), ActualF, ExpectedF, 0.001f); // tolerance overload
// Boolean
TestTrue(TEXT("Label"), bCondition);
TestFalse(TEXT("Label"), bCondition);
// Pointer / validity
TestNotNull(TEXT("Label"), Ptr); // fails if Ptr == nullptr
TestNull(TEXT("Label"), Ptr); // fails if Ptr != nullptr
TestValid(TEXT("Label"), WeakPtr); // IsValid() check on TWeakObjectPtr etc.
// Custom failure messages
AddError(FString::Printf(TEXT("Unexpected damage %d"), Damage));
AddWarning(TEXT("Deprecated path hit"));
// Add error and bail — returns false from RunTest if condition fails
UE_RETURN_ON_ERROR(Ptr != nullptr, TEXT("Ptr must not be null"));Test Flags Reference
| Flag | Meaning |
|---|---|
EditorContext | Runs in the editor process |
ClientContext | Runs in game client |
ServerContext | Runs on dedicated server |
SmokeFilter | Fast; runs on every CI check-in |
ProductFilter | Project/game-level tests |
Latent Commands (Async Testing)
Use latent commands when the test must wait for an async operation. Update() returns true when done, false to retry next frame.
DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(FWaitSecondsCommand, float, Duration);
bool FWaitSecondsCommand::Update() { return GetCurrentRunTime() >= Duration; }
// Enqueue inside RunTest; commands drain sequentially after RunTest returns
ADD_LATENT_AUTOMATION_COMMAND(FWaitSecondsCommand(2.0f));See references/automation-test-patterns.md for delegate-wait, timeout, and post-async assertion patterns.
Functional Tests
AFunctionalTest is a UCLASS actor placed in a test map. Override StartTest() and call FinishTest() when done.
// MyFunctionalTest.h
UCLASS()
class MYGAMETESTS_API AMyFunctionalTest : public AFunctionalTest
{
GENERATED_BODY()
public:
virtual void StartTest() override;
private:
UFUNCTION() void OnTimerExpired();
FTimerHandle TimerHandle;
};
// MyFunctionalTest.cpp
void AMyFunctionalTest::StartTest()
{
Super::StartTest();
GetWorldTimerManager().SetTimer(TimerHandle, this,
&AMyFunctionalTest::OnTimerExpired, 1.0f, false);
}
void AMyFunctionalTest::OnTimerExpired()
{
bool bPassed = /* verify world state */ true;
FinishTest(bPassed ? EFunctionalTestResult::Succeeded
: EFunctionalTestResult::Failed,
TEXT("Timer-based check"));
}Place actors in Maps/Test_MyFeature.umap. Run via RunAutomationTest "MyGame.Functional.MyFeature" or the Session Frontend.
TimeLimit
// Timeout — auto-fail if test exceeds time limit
void AMyFunctionalTest::PrepareTest()
{
Super::PrepareTest();
TimeLimit = 10.0f; // seconds; 0 = no timeout (default)
}Logging
Declaring and Defining a Category
// MyModule.h — visible across the module
DECLARE_LOG_CATEGORY_EXTERN(LogMyModule, Log, All);
// ^Name ^Default ^CompileTime max
// MyModule.cpp
DEFINE_LOG_CATEGORY(LogMyModule);
// Single-file static category (no extern needed)
DEFINE_LOG_CATEGORY_STATIC(LogMyHelper, Warning, All);UE_LOG Usage
// UE_LOG(CategoryName, Verbosity, Format, ...)
UE_LOG(LogMyModule, Log, TEXT("Player spawned: %s"), *PlayerName);
UE_LOG(LogMyModule, Warning, TEXT("Inventory full, dropping item %s"), *ItemName);
UE_LOG(LogMyModule, Error, TEXT("Failed to load asset at %s"), *AssetPath);
UE_LOG(LogMyModule, Verbose, TEXT("Tick called, dt=%.4f"), DeltaTime);
UE_LOG(LogMyModule, Fatal, TEXT("Unrecoverable save corruption")); // crashes
// Conditional log — condition evaluated only if category/verbosity is active
UE_CLOG(Health <= 0.f, LogMyModule, Warning, TEXT("Actor %s has zero health"), *GetName());Verbosity Levels (highest to lowest severity)
| Level | When to use |
|---|---|
Fatal | Crash-worthy unrecoverable errors |
Error | Operation failed, needs developer attention |
Warning | Unexpected but recoverable condition |
Display | User-visible output (always shown) |
Log | Standard development info |
Verbose | Detailed per-frame or per-call info |
VeryVerbose | Trace-level; very high frequency |
Structured Logging (UE 5.2+)
#include "Logging/StructuredLog.h"
// Named fields — order does not matter; extra fields beyond the format string are allowed
UE_LOGFMT(LogMyModule, Warning,
"Loading '{Name}' failed with error {Error}",
("Name", AssetName), ("Error", ErrorCode), ("Flags", LoadFlags));Runtime Log Filtering
# Command line: set a category to Verbose at startup
-LogCmds="LogMyModule Verbose, LogAI Warning"
# Console at runtime
Log LogMyModule Verbose
Log LogAI Warning
Log reset # restore defaultsAssertions
More from quodsoler
Use this skill in a project
Open any RiverX project, search the Skills panel for quodsoler/unreal-engine-skills/ue-testing-debugging, and install it in one click.
