Tests in UE4 - Automation Tool

  • *dead*
  • :bye:
  • :ass:
  • :lol:
  • :laughing:
  • :)
  • :(
  • ;)
  • :P
  • ^^
  • :D
  • ;(
  • X(
  • :*
  • :|
  • 8o
  • =O
  • <X
  • ||
  • :/
  • :S
  • X/
  • 8)
  • ?(
  • :huh:
  • :rolleyes:
  • :love:
  • 8|
  • :cursing:
  • :thumbdown:
  • :thumbup:
  • :sleeping:
  • :whistling:
  • :evil:
  • :saint:
  • <3
  • :!:
  • :?:
  • :sleep:
  • :__
  • :sleepy:
  • :sparki:
  • :gamemaker:
  • :pinguin:
  • Hier wird das Thema Testen in der UE4 behandelt. Einleitend ein paar Worte dazu, was Tests sind und wozu man sie braucht. Dann werden die verschiedenen Testarten, die die UE4 anbietet, besprochen. Im Hauptteil wird darauf eingegangen, wie man seine Testfunktionen definiert.

    Aktuell fehlen noch ein paar Beispiele für Tests und wie man zB. einen Actor in der Welt Spawnen lässt während des testens.

    Vorab
    Die hier aufgelisteten Informationen beziehen sich auf UE4.10.0. Die Testumgebung hat sich immer wieder stark verändert und viele der Antworten da draußen funktionieren nicht mit 4.10.
    Tests lassen sich meines Wissen nach nicht in Form von Blueprints schreiben. Dies wird ein C++ Eintrag.
    Vieles davon ist aus der Dokumentation übernommen. Außerdem Poste ich schnipsel aus dem Quellcode der Unreal Engine, die auch sonst frei zugänglich sind.



    Wozu testen?
    Man kann dazu erst einmal sagen, dass es notwendig ist zu testen, da dies die Anzahl der Bugs reduziert. Das sollte also folglich die Qualität eurer Spiele erhöhen.



    Wie laufen Tests theoretisch ab?



    1. Definieren, was eine Funktion kann und tun soll.
    2. Test schreiben, der verschiedene Eingaben in die Funktion gibt.
    3. Ergebnis/Rückgabe der Funktion gegen die erwarteten Werte prüfen und Test als bestanden / nicht bestanden deklarieren.
    4. die Funktion schreiben und testen



    Wenn man das mit allen Funktionen macht (was unüblich ist, da es doch einiges an Arbeit kostet) könnt ihr euch so sicher sein, dass euer System robust ist. Sinn macht es vor allem, wenn sich eure Programme weiterentwickeln und die Funktionen auch von immer mehr Leuten aus eurem Team genutzt werden sollen.



    Was gibt es für Tests?



    Ich verlinke mal die Doku dazu.
    docs.unrealengine.com/latest/I…TechnicalGuide/index.html



    Ich habe noch weiter gesucht. Das Automation Tool kennt mehrere Flags (ATF_...)
    ATF_Editor
    Diese Tests scheinen (unsicher) dazu da zu sein, um im laufenden Editor Funktionen des Editors zu testen.
    Diese sind im SessionFrontend ausführbar



    ATF_Game
    Diese Tests werden während das Spiel läuft durchgeführt. Aktuell funktioniert das nicht im Editor. Wie sowas trotzdem getestet werden kann verrate ich weiter unten. Alles was die GEngine benötigt (zum Beispiel ein Level laden) ist von diesem Typ.



    ATF_SmokeTest
    Damit werden Funktionen auf den untersten Levels getestet. Gemeint sind Funktionen, die keine oder sehr wenige Abhängigkeiten haben und in der Regel auch sehr schnell durchlaufen.
    Diese sind im SessionFrontend ausführbar.



    ATF_Commandlets
    Diese werden sozusagen auf der Console ausgeführt. Man braucht hier also eine Console...



    Es gibt noch einige weitere, die auch jeweils Bedingungen zum Testen ausdrücken. Das ganze sorgt dafür, dass Tests nicht in unzureichender Umgebung durchgeführt werden.



    Wie definiere ich einen Test?



    Einige Probleme könnten auf fehlende Includes zurückzuführen sein.



    C
    1. #include "MyGame.h" //replace with your Project Name
    2. #include "AutomationCommon.h" //if you use ATF_Game
    3. #include "UnrealEd.h" // if you use ATF_Editor
    4. ... more
    5. #include "TheClassYouWantToWriteTheTestFor.h"


    Die Engine hält 2 Makros für uns bereit, die bei der Erstellung von Tests behilflich sind.


    C
    1. IMPLEMENT_SIMPLE_AUTOMATION_TEST( TClass, PrettyName, TFlags )
    2. IMPLEMENT_COMPLEX_AUTOMATION_TEST( TClass, PrettyName, TFlags )


    Als Beispiel ein Test:


    C
    1. IMPLEMENT_SIMPLE_AUTOMATION_TEST(TFunctionIWantToTestTest, "MyGame.ClassName.FunctionName", EAutomationTestFlags::ATF_SmokeTest)
    2. bool TFunctionIWantToTestTest::RunTest(const FString& Parameters)
    3. {
    4. //todo: implement
    5. // False, da die Funktionalität ja nicht bestätigt wurde...
    6. return false;
    7. }

    Zum Komplex Test:
    Hierfür müsst ihr zusätzlich zur RunTest() auch noch eine GetTest() Funktion überschreiben.


    Logausgaben sind auch möglich:


    In AutomationCommon.h werden folgende Logausgaben definiert:


    C
    1. DEFINE_LOG_CATEGORY_STATIC(LogEditorAutomationTests, Log, All);
    2. DEFINE_LOG_CATEGORY_STATIC(LogEngineAutomationTests, Log, All);
    3. DEFINE_LOG_CATEGORY_STATIC(LogAnalytics, Log, All);


    Verwendung mit variablen Text:


    C
    1. UE_LOG(LogEngineAutomationTests, Log, TEXT("Loading Map Now: %s "), *MapName);


    Was sind Latent Commands?


    Auf Latent Commands wird in der Doku nur sehr kurz eingegangen. Diese sind für alle Funktionen vorgesehen, die über mehr als ein Frame dauern. Zum Beispiel eine Sekunde warten oder eine Map laden. Networking sollte auch darunter fallen.



    C
    1. DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(FExecStringLatentCommand, FString, ExecCommand);
    2. bool FExecStringLatentCommand::Update()

    Der Schnipsel oben sollte zum ausführen von Consolen-Kommandos bereits irgendwo definiert sein. Um diesen zu benutzen schreibt in euren Test (oben //todo:implement):



    Code
    1. ADD_LATENT_AUTOMATION_COMMAND(FExecStringLatentCommand(TEXT("setres 640x480")));


    Mir ist bei Latent Commands ein Linkerfehler aufgetreten, der die Update() von FLoadGameMapCommand Funktion nicht richtig verlinkt hat. In dem Fall könnt ihr die einfach überschreiben.



    Beispiel zum Map laden:


    C
    1. bool FLoadGameMapCommand::Update()
    2. {
    3. check(GEngine->GetWorldContexts().Num() == 1);
    4. check(GEngine->GetWorldContexts()[0].WorldType == EWorldType::Game);
    5. UE_LOG(LogEngineAutomationTests, Log, TEXT("Loading Map Now. '%s'"), *MapName);
    6. GEngine->Exec(GEngine->GetWorldContexts()[0].World(), *FString::Printf(TEXT("Open %s"), *MapName));
    7. return true;
    8. }


    Wie führe ich einen Test aus?



    Die meisten Tests lassen sich im Editor->Window->DeveloperTools->SessionFrontend ausführen. Nicht so die ATF_Game Tests. Dazu braucht ihr eine packaged/cooked Version des Spiels. Alle Tests, auch die von Epic bereits erstellten lassen sich mit dieser batch Datei ausführen:



    Code
    1. @ECHO OFF
    2. Set UE4EnginePath=D:\Unreal\Unreal Engine\4.10\Engine :: Beispielpfad
    3. Set ProjectPath=D:\GameDev\Repo :: Beispielpfad
    4. start "Testing" "%UE4EnginePath%\Build\BatchFiles\RunUAT.bat" BuildCookRun -project=%ProjectPath%\MyGame.uproject -run -RunAutomationTests -unattended -nullrhi -NoP4


    Wir haben jedem Test einen sogenannten prettyname gegeben. Die Worte wurden mit . voneinander getrennt. Diese Unterteilung macht sich beim Ausführen von ATF_Game Tests durchaus bezahlt. Mit dem Schnipsel unten als batch ausgeführt, lassen sich die Tests der ausgewählten Kategorie ausführen. Gut daran ist auch, dass die Console offen bleibt und man in rot sieht, welche Tests fehlgeschlagen sind. Ich hänge trotzdem mal noch ein kleines python Progrämmchen an, was einem die Tests, Fehler und Warnungen aus Logs in eine Datei zaubert, die dann neben dem Python file liegen sollte. Sofern ein Python Interpreter installiert ist kann man das über die Console mit python ErrorLogger.py ausführen.dl.dropboxusercontent.com/u/58457747/ErrorLogger.py Ihr müsst noch die Pfade am Anfang anpassen, damit es funktioniert. Das geht mit fast jedem Texteditor.



    Code
    1. start "Testing" "%UE4EnginePath%\Build\BatchFiles\RunUAT.bat" BuildCookRun -project=%ProjectPath%\MyGame.uproject -run -RunAutomationTest=Mygame.ModuleA -unattended -nullrhi -NoP4


    Bei Fragen, Anmerkungen und so weiter kommentiert gern hier drunter, ich arbeite das dann ein und lösche / lasse löschen, was beantwortet wurde.

Teilen