Wie führt man Unit-Tests in einer Game-Engine durch?

23

Sehr zu meiner Schande habe ich noch nie einen richtigen Komponententest geschrieben, sondern nur kleine unorganisierte Testprogramme, die ich nach erfolgreichem Test entsorgen würde. Ich habe keine klare Vorstellung davon, wie Unit-Tests in einem Spielprojekt durchgeführt werden sollten. (Meine Sprache ist C ++.)

Sollte ich für jedes Subsystem in meinem Motor ein separates Projekt und einen zugehörigen Test haben und dann ein größeres Projekt / eine größere Lösung, die den eigentlichen Motor erstellt? Angenommen, ich habe das eventModul in meinem Motor. wie soll ich damit umgehen

Paul Manta
quelle
interessante Frage, wenn Sie Ihre Engine entwickeln, ist es ziemlich einfach, die Funktionalität zu testen, aber was ist mit großen Projekten im Spieltest?
Yevhen
2
Keine Schande: Unit-Tests sind nicht automatisch eine gute Sache.
o0 '.
1
Wenn Sie noch nie Unit-Tests ausprobiert haben, ist das definitiv eine Schande.
Kristopher Johnson

Antworten:

18

Zunächst benötigen Sie ein Unit-Testing-Framework. In der Vergangenheit habe ich UnitTest ++ und Google Test verwendet . Ersteres ist sehr leicht und letzteres ist mehr ausgestattet, aber etwas umständlicher. Es lässt sich gut in Google Mock integrieren, falls Sie so etwas jemals brauchen sollten. Es gibt natürlich viele andere Möglichkeiten: siehe diese Liste (vom eventuellen Autor von UnitTest ++) und Wikipedia zum Beispiel.

Beim Unit-Testen geht es darum, fokussierte Tests zu schreiben, um bestimmte isolierte unabhängige Codebits ("Units") unter verschiedenen Szenarien hervorzuheben. In einigen Fällen können Sie alles Unit-testen. In der Regel ist es jedoch nicht praktisch, eine 100-prozentige Abdeckung zu erzielen. Insbesondere in Spielen kann dies recht schwierig sein. Es ist fraglich, ob Unit-Tests Ihrer Renderer-Ausgabe in irgendeiner Weise sinnvoll, nützlich oder sinnvoll sind ein "wahrer" Komponententest, egal.

Es ist wichtig, sich daran zu erinnern, dass jedes (automatisierte) Testen besser ist als kein (automatisiertes) Testen. Sie sollten also nicht zu viel Wert darauf legen, dass Ihre Tests keine "echten Komponententests" sind, und stolz darauf sein, dass Sie nur Tests haben. Unit-Test-Frameworks sind in der Regel nützlich, um lockerere, "nicht-Unit" -Tests zu erstellen, da sie Funktionen für Verpackungstests und die einheitliche Meldung von Fehlern enthalten.

Ich würde Sie ermutigen, Ihre alten Tests erneut zu beleben und sie mit einem der verfügbaren Frameworks in ein Testprojekt zu integrieren - etwas, das Sie von Zeit zu Zeit (oder automatisch als Teil eines Release- oder Integrationsbuilds) problemlos ausführen können, das alle ausführt Ihre Tests. Schreiben Sie neue Tests für Code-Teile, wenn sich herausstellt, dass diese für Sie nützlich sind. Wenn Sie beispielsweise einen subtilen Fehler entdecken, den Sie mit einem Test hätten entdecken können, können Sie einen hinzufügen, um eventuelle zukünftige Regressionen zu erfassen.

Sie werden wahrscheinlich feststellen, dass es hauptsächlich Ihr niedrigerer Utility-Code ist, der für Unit-Tests in Spielen geeignet ist. Das ist in Ordnung - das ist Foundation Code, der viele höhere Ebenen stören kann, wenn er kaputt geht.

Sie werden nicht zum Fegefeuer des Programmierers gehen, weil Sie keine Tests für jede kleine Funktion und jedes logische Gatter in Ihrer Codebasis haben. Nehmen Sie sich also nicht mehr Zeit, als Sie für das Schreiben von Tests benötigen. Wenn Sie überlegen müssen oder wesentlich mehr Zeit mit dem Schreiben der Tests für ein Modul verbringen, als Sie zum Erstellen des Moduls benötigt haben, verschwenden Sie möglicherweise Ihre Zeit. Unit Testing - Testen im Allgemeinen - ist ein Werkzeug, mit dem Sie lernen, wie Sie es angemessen einsetzen, um Ihnen zu helfen, und keine Arbeit, die Sie für alles ausführen müssen.

Josh
quelle
3
If you have to [...] spend significantly more time writing the tests [...] than it took you to author the module... dann ist Ihr Modul zu komplex. Vereinfachen Sie es jetzt, Sie werden sich in Zukunft bedanken!
Jess Telford
3
@Jess Ein Modul, das unverhältnismäßig schwer zu testen ist, muss nicht unbedingt vereinfacht werden. Es gibt viele Bereiche, in denen Unit-Tests einfach keine gute Zeit sind. Dies schließt Grafiken ein, bei denen die Ausgabe stark variieren kann und dennoch akzeptabel ist. Code, der sich in Zukunft wahrscheinlich nicht mehr ändern wird; oder Code, bei dem die Art des abstrakten, entkoppelten Designs, das zum Ermöglichen von Komponententests erforderlich wäre, viel hässlicher, fehleranfälliger, weniger performant oder weniger intuitiv ist.
Casey Rodarmor
@rodarmor - einverstanden. Es gibt eine gleitende Skala, was angemessen ist und was nicht. Wie bei all diesen Arten von Antworten, passt eine Größe nicht für alle :)
Jess Telford
Für UnitTest ++ gehen Sie zu github.com/unittest-cpp/unittest-cpp . Alles andere ist veraltet.
Markus
4

Eine "Einheit" ist der kleinste prüfbare Code, normalerweise eine einzelne Funktion oder Klasse. Ein Unit-Test ist ein weiterer Code, der diese Code-Unit ausübt, um sicherzustellen, dass sie sich wie beabsichtigt verhält. Eine einzelne Codeeinheit kann viele Tests haben, um alle Fälle abzudecken.

In der Regel sind Tests nicht im Hauptbuild eines Projekts enthalten. Vielmehr gibt es eine separate Build-Konfiguration zum Testen, die den gesamten Testcode enthält und ein Programm erstellt, das alle Tests ausführt und die Ergebnisse meldet. Ein Test-Framework wird das gesamte Gerüst dafür bereitstellen und wird empfohlen, obwohl dies nicht unbedingt erforderlich ist. Wenn Sie mit dem Testen völlig neu sind, ist es möglicherweise besser, zuerst einen eigenen Ad-hoc-Prüfstand zu schreiben, um sicherzustellen, dass Sie alles verstehen, was gerade passiert.

Decken Sie so viel Code wie möglich mit Tests ab und priorisieren Sie Code, bei dem Sie sich nicht sicher sind, oder Code, der zerbrechlich ist und möglicherweise durch zukünftige Änderungen beschädigt wird. Sie sollten die Tests häufig ausführen, idealerweise nach jeder Codeänderung.

jedediah
quelle