Language:
Page Info
Skill Level:
Engine Version:

自動化に関するテクニカルガイド

自動化テスト

Automation Testing (自動化テスト) は、自動化テストの最低レベルのテストで、エンジンのコア機能の低レベル テストに最適です。このシステムは、UObject エコシステムの外部にあり、ブループリント やエンジンの リフレクション システム からは見えません。こうしたテストはビルトインのコードで、コンソールのコマンドライン から、エディタ内で、またはオペレーティング システムのコマンドライン パラメータで実行することができます。自動化テストは、簡易テストと複合テストの二通りがあります。両方とも、FAutomationTestBase をベースにした派生クラスとして実装されます。

新規自動化テストの作成

自動化テストはマクロによって宣言され、FAutomationTestBase クラスから仮想関数をオーバーライドすることで実装されます。簡易テストは IMPLEMENT_SIMPLE_AUTOMATION_TEST マクロを使用して宣言します。一方、複合テストでは、IMPLEMENT_COMPLEX_AUTOMATION_TEST マクロが必要になります。これらのマクロは両方とも以下の順序の同じ 3 つのマクロを特徴とします。

パラメータ

説明

TClass

テストのクラス名です。マクロは、この名前のクラス、例えば、テストを実装できる FPlaceholderTest といったクラスを作成します。

PrettyName

UI に表示される階層的なテストの名前を指定した文字列です。例えば、最小限の例の "TestGroup.TestSubgroup.Placeholder Test" です (以下)。

TFlags

EAutomationTestFlags 値の組み合わせであり、自動化テストの要件と挙動を指定するために使われます。詳細については、EAutomationTestFlagsEAutomationTestFlags API Page をご覧ください。

新規 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 つのパラメータをとります。ParamTypeParamName で、それぞれ渡すパラメータのタイプと名前を定義します。この例では、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()));

データのロードやストリーミングに関する動作や、単一フレームで実行できる保証がないものは、Latent コマンドを使用する対象になります。例えば、エディタではマップのロードはただちに起こりますが、ゲームではマップのロードは次のフレームで起こります。従って、自動化テストでマップのロードが必要な場合、Latent コマンドを使って確実に一貫性のある挙動になるようにします。