自動化テスト
Automation Testing (自動化テスト) は、自動化テストの最低レベルのテストで、Unreal Engine のコア機能の低レベル テストに最適です。このシステムは、UObject
エコシステムの外部にあり、ブループリント やエンジンの リフレクション システム からは見えません。こうしたテストはビルトインのコードで、コンソールのコマンドライン から、エディタ内で、またはオペレーティング システムの コマンドライン パラメータ で実行することができます。自動化テストは、簡易 テストと 複合 テストの二通りがあります。両方とも、FAutomationTestBase
をベースにした派生クラスとして実装されます。
自動化テストを新規作成する
自動化テストはマクロによって宣言され、FAutomationTestBase
クラスから仮想関数をオーバーライドすることで実装されます。簡易テストは IMPLEMENT_SIMPLE_AUTOMATION_TEST
マクロを使用して宣言します。一方、複合テストでは、IMPLEMENT_COMPLEX_AUTOMATION_TEST
マクロが必要になります。これらのマクロは両方とも以下の順序の同じ 3 つのマクロを特徴とします。
パラメータ | 説明 |
---|---|
TClass |
テストのクラス名です。マクロは、この名前のクラス、例えば、テストを実装できる FPlaceholderTest といったクラスを作成します。 |
PrettyName |
UI に表示される階層的なテストの名前を指定した文字列です。例えば、最小限の例の "TestGroup.TestSubgroup.Placeholder Test" です (以下)。 |
TFlags |
EAutomationTestFlags 値の組み合わせであり、自動化テストの要件と挙動を指定するために使われます。詳細については、EAutomationTestFlags API ページ を参照してください。 |
新規 Automation Test クラスが以下の 2 つのマクロのひとつによって宣言されたら、その機能を実装することができます。以下の関数を記述しなければなりません。
関数 | パラメータ | 説明 |
---|---|---|
RunTest |
実際のテストを行い、テストに合格すると true を戻し、失敗すると false を戻します。 |
|
Parameters |
特定の機能テストのためにパースされるか、必要に応じて他の関数に渡されます。 | |
GetTests |
複合テストに限りオーバーライドされなくてはなりません。簡易テストの場合は、この関数の自動生成バージョンが宣言用マクロに組み込まれています。 | |
OutBeautifiedNames |
この文字列には、UI に表示される各テストの PrettyName が入ります。 |
|
OutTestCommands |
この文字列は、OutBeautifiedNames と並列し、RunTest に渡される Parameters が入ります。 |
ソース ファイルの場所
現在の決まりでは、全ての自動化テストは、関連モジュール内の Private\Tests
ディレクトリに入ります。自動化テストが特定クラスと一対一で一致した時、テストファイル名を [ClassFilename]Test.cpp
としてください。例えば、FText
だけに適用されるテストは、TextTest.cpp
になります。
最小限の例
可能な限り、最小限かつ単純なテストは、簡易テストであり、自動的に合格 (または不合格) になります。このようなテストのビルドは、さらに重要なテストをビルドする前に、セットアップを確実に正しいものにする最初のステップとして役立ちます。
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FPlaceholderTest, "TestGroup.TestSubgroup.Placeholder Test", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
bool FPlaceholderTest::RunTest(const FString& Parameters)
{
// Make the test pass by returning true, or fail by returning false.
return true;
}
簡易テスト
簡易テスト は、単一のアトミックなテストを表し、ユニット テストまたは機能テストとして便利です。例えば、簡易テストは現在のマップが Play In Editor (PIE) にロードされるか、テキストのラッピングがスレートで正しく機能しているかをテストするために使用することができます。以下の例では、SetRes
コマンドの機能をテストしています。
IMPLEMENT_SIMPLE_AUTOMATION_TEST( FSetResTest, "Windows.SetResolution", ATF_Game )
bool FSetResTest::RunTest(const FString& Parameters)
{
FString MapName = TEXT("AutomationTest");
FEngineAutomationTestUtilities::LoadMap(MapName);
int32 ResX = GSystemSettings.ResX;
int32 ResY = GSystemSettings.ResY;
FString RestoreResolutionString = FString::Printf(TEXT("setres %dx%d"), ResX, ResY);
ADD_LATENT_AUTOMATION_COMMAND(FEngineWaitLatentCommand(2.0f));
ADD_LATENT_AUTOMATION_COMMAND(FExecStringLatentCommand(TEXT("setres 640x480")));
ADD_LATENT_AUTOMATION_COMMAND(FEngineWaitLatentCommand(2.0f));
ADD_LATENT_AUTOMATION_COMMAND(FExecStringLatentCommand(RestoreResolutionString));
return true;
}
複合テスト
複合テスト は、同じコードを複数の入力に対して実行します。これは通常はコンテンツ負荷テストです。例えば、すべてのマップのロードやすべてのブループリントのコンパイルは、複合自動化テストに適しています。RunTest
関数と GetTests
関数は両方ともオーバーライドされなければなりません。以下のサンプルは、すべてのプロジェクト マップのロードをテストします。
IMPLEMENT_COMPLEX_AUTOMATION_TEST(FLoadAllMapsInGameTest, "Maps.LoadAllInGame", ATF_Game)
void FLoadAllMapsInGameTest::GetTests(TArray<FString>& OutBeautifiedNames, TArray <FString>& OutTestCommands) const
{
FEngineAutomationTestUtilities Utils;
TArray<FString> FileList;
FileList = GPackageFileCache->GetPackageFileList();
// Iterate over all files, adding the ones with the map extension..
for( int32 FileIndex=0; FileIndex< FileList.Num(); FileIndex++ )
{
const FString& Filename = FileList[FileIndex];
// Disregard filenames that don't have the map extension if we're in MAPSONLY mode.
if ( FPaths::GetExtension(Filename, true) == FPackageName::GetMapPackageExtension() )
{
if (!Utils.ShouldExcludeDueToPath(Filename))
{
OutBeautifiedNames.Add(FPaths::GetBaseFilename(Filename));
OutTestCommands.Add(Filename);
}
}
}
}
bool FLoadAllMapsInGameTest::RunTest(const FString& Parameters)
{
FString MapName = Parameters;
FEngineAutomationTestUtilities::LoadMap(MapName);
ADD_LATENT_AUTOMATION_COMMAND(FEnqueuePerformanceCaptureCommands());
return true;
}
Parameters
引数をビルドしてパースすることができます。複合テストの場合、いくつかのデータ ポイントを同じコードを使ってテストするために使う方法です。Latent コマンド
Latent (潜在) コマンド を RunTest
中に待ち行列に入れて、コードのセクションを複数のフレームで実行することができます。Latent Action を作成するには、DEFINE_LATENT_AUTOMATION_COMMAND
マクロで定義しなければなりません。このマクロは、CommandName
というパラメータをとります。これは、この種の Latent コマンドで作成されるクラス名を定義します。Latent コマンドの作成を完了するには、その新規クラスで Update
関数の関数ボディを必要とします。以下はシンプルな Latent コマンドの例です。Unit Test Manager がテスト実行を終了するまで実行します。
DEFINE_LATENT_AUTOMATION_COMMAND(FNUTWaitForUnitTests);
bool FNUTWaitForUnitTests::Update()
{
return GUnitTestManager == NULL || !GUnitTestManager->IsRunningUnitTests();
}
作成する Latent コマンドがパラメータ文字列などの引数を必要とする場合、DEFINE_LATENT_AUTOMATION_COMMAND
マクロを使用することができます。このマクロはさらに 2 つのパラメータをとります。ParamType
と ParamName
で、それぞれ渡すパラメータのタイプと名前を定義します。この例では、Latent コマンドを使ってソース コントロール プロバイダーへの接続を開始し、接続の試みが終了するまで待機します。
DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(FConnectLatentCommand, SourceControlAutomationCommon::FAsyncCommandHelper, AsyncHelper);
bool FConnectLatentCommand::Update()
{
// Attempt a login and wait for the result.
if(!AsyncHelper.IsDispatched())
{
if(ISourceControlModule::Get().GetProvider().Login( FString(), EConcurrency::Asynchronous, FSourceControlOperationComplete::CreateRaw( &AsyncHelper, &SourceControlAutomationCommon::FAsyncCommandHelper::SourceControlOperationComplete ) ) != ECommandResult::Succeeded)
{
return false;
}
AsyncHelper.SetDispatched();
}
return AsyncHelper.IsDone();
}
Update
関数が true
を戻すと、Latent コマンドが完了したと考えられます。戻り値が false
の場合、自動化テストはただちに実行を停止し、次のフレームで再度実行を試みます。テスト コードで Latent コマンドを使用するには、実行する Latent コマンドのコンストラクタで ADD_LATENT_AUTOMATION_COMMAND
を呼び出します。Latent コマンドでパラメータを設定したら、その値を、パラメータがコンストラクタの引数として取る値として渡します。RunTest
関数で、以下のコードはすべてのユニット テストが終わるまで待機し、以前名前を付けたソース コントロール プロバイダに接続しようとします。
ADD_LATENT_AUTOMATION_COMMAND(FNUTWaitForUnitTests());
ADD_LATENT_AUTOMATION_COMMAND(FConnectLatentCommand(SourceControlAutomationCommon::FAsyncCommandHelper()));