Wie kann man die Software eines Spiels so gestalten, dass es leicht ist, einen Komponententest durchzuführen?

25

Ist es praktisch, ein Testframework wie JUnit in einer Spieleentwicklungssituation zu verwenden? Welche Art von Design-Überlegungen können Sie befolgen, um Ihr Spiel testbarer zu machen? Welche Teile eines Spiels können / sollten getestet werden und welche Teile sollten / müssen menschlichen Tests überlassen werden?

Wenn zum Beispiel die Spieleschleife in einer Funktion verkapselt ist, scheint es schrecklich schwierig zu sein, sie zu testen. Ich möchte eine "Update" -Funktion überarbeiten, die ein Zeitdelta benötigt und die Spiellogik vorantreibt. Dies ermöglicht einige interessante Tricks wie die Fähigkeit, das Spiel zu verlangsamen, indem es mit falschen, langsameren Zeitdeltas gefüttert wird.

Ricket
quelle
6
Warum sollten Sie Zeit mit dem Schreiben von Einheitentests verschwenden? Ich Kind, ich Kind ...;)
Mike Strobel
1
Eigentlich braucht man kein Kind, das ist ein wirklich guter Punkt! Ich habe nicht darüber nachgedacht, aber Spiele sind die einfachste Art von Software, mit der andere Leute testen können. Ich vermute, dass dies die Schwierigkeit automatisierter Spieletests (in Einheiten oder auf andere Weise) etwas ausgleichen kann.
Ricket
3
Beim Komponententest muss nicht unbedingt sichergestellt werden, dass Ihre Anwendung als Ganzes ordnungsgemäß funktioniert (z. B. Funktionstests). Es geht vielmehr darum, sicherzustellen, dass zukünftige Änderungen die vorhandenen Funktionen nicht beeinträchtigen. Sicher, ein Benutzer kann sehen, wann das Raumschiff auf dem Kopf steht, aber wenn der Suchalgorithmus um 0,001 Uhr deaktiviert ist, sind die Auswirkungen möglicherweise erst sichtbar, wenn das Spiel 200 Stunden lang gespielt wird. Das ist die Art von Dingen, die Unit-Tests erfassen können, bevor der Code jemals aus der Tür geht.
Wade Williams
1
Spiele sind die einfachste Software, mit der Benutzer zum Spielen gebracht werden können , aber sie spielen! = Testen . Gute Fehlerberichte zu bekommen ist ziemlich schwierig. Darüber hinaus profitieren Sie von automatisierten Tests, wenn Sie feststellen, wo im Code ein Fehler auftritt, und überprüfen, ob neue Änderungen den vorhandenen Code nicht beschädigen.
Munificent

Antworten:

25

Einer der Grundsätze von TDD ist, dass Sie TDD in einigen Fällen Ihr Design beeinflussen lassen. Sie schreiben einen Test für das System und schreiben dann den Code, damit dieser Test bestanden wird. Halten Sie die Abhängigkeiten so gering wie möglich.

Für mich gibt es nur zwei Dinge, die ich im Rahmen von Unit-Tests nicht teste:

Erstens teste ich keine visuellen Elemente und wie die Dinge aussehen. Ich teste das und das Objekt wird an der richtigen Stelle sein, nachdem es aktualisiert wurde. Eine Kamera wird ein Objekt außerhalb seiner Grenzen aussortieren, die Transformationen (zumindest die, die außerhalb von Shadern durchgeführt werden) werden ordnungsgemäß durchgeführt, bevor sie an die Grafik-Engine übergeben werden , aber sobald es das Grafiksystem trifft, zeichne ich die Linie. Ich mag es nicht, Dinge wie DirectX zu verhöhnen.

Zweitens teste ich die Hauptspielschleifenfunktion nicht wirklich. Ich teste, dass jedes System funktioniert, wenn ein vernünftiges Delta überschritten wird, und dass die Systeme bei Bedarf ordnungsgemäß zusammenarbeiten. Dann aktualisiere ich einfach jedes System mit dem richtigen Delta in der Spielschleife. Ich könnte tatsächlich einen Test haben, um zu zeigen, dass jedes System mit dem richtigen Delta aufgerufen wurde, aber in vielen Fällen finde ich diesen Overkill (es sei denn, Sie führen eine komplexe Logik aus, um Ihr Delta zu erhalten, dann ist es kein Overkill).

Jeff
quelle
6
Der erste Absatz ist der Schlüssel. Tatsache ist, dass TDD von Ihnen verlangt, dass Sie Ihren Code besser entwerfen als ohne ihn, nur um das Testen zu ermöglichen. Natürlich denken viele, dass sie Experten im Design sind, aber natürlich sind die, die am meisten von ihren eigenen Fähigkeiten beeindruckt sind, normalerweise die, die am meisten lernen ...
dash-tom-bang
2
Ich würde nicht zustimmen, dass der Code als Ergebnis notwendigerweise besser gestaltet ist. Ich habe viele Abscheulichkeiten gesehen, bei denen eine zuvor saubere Schnittstelle aufgebrochen und die Kapselung aufgebrochen werden musste, um testbare Abhängigkeiten zu erzeugen.
Kylotan
4
Ich finde, dass dies eher in Fällen der Fall ist, in denen Tests für bereits vorhandene Klassen geschrieben wurden, als umgekehrt.
Jeff
@Kylotan, das ist wahrscheinlich eher ein Symptom für falsches Design / schlechtes Testdesign. Überarbeiten und verwenden Sie Mocks, um saubere Tests durchzuführen. Hacken Sie Ihren Code nicht in einen schlechteren Zustand. Das ist das Gegenteil von dem, was passieren soll.
Timoxley
2
Kapselung ist eine gute Sache, aber umso wichtiger ist es zu verstehen, WARUM es eine gute Sache ist. Wenn Sie es nur verwenden, um Abhängigkeiten und eine große hässliche Benutzeroberfläche zu verbergen, ist es ziemlich belastend, dass Ihr Design unter der Haube wahrscheinlich nicht sehr schön ist. Bei der Kapselung geht es in erster Linie nicht darum, hässlichen Code und Abhängigkeiten zu verbergen, sondern in erster Linie darum, Ihren Code verständlicher zu machen und dem Konsumenten weniger Wege zu bieten, wenn er versucht, über den Code nachzudenken.
Martin Odhelius
19

Noel Llopis hat Unit-Tests in dem Maße behandelt, wie Sie es meines Erachtens suchen:

In Bezug auf das Testen der gesamten Spielschleife gibt es eine andere Technik, um funktionale Regressionen in Ihrem Code zu verhindern. Die Idee ist, Ihr Spiel selbst über ein Wiedergabesystem spielen zu lassen (dh zuerst Spielereingaben aufzuzeichnen und sie dann über einen anderen Lauf wiederzugeben). Während der Wiedergabe generieren Sie für jedes Bild eine Momentaufnahme des Status jedes Objekts. Diese Staatssammlung kann dann als "goldenes Bild" bezeichnet werden. Wenn Sie Ihren Code überarbeiten, führen Sie die Wiedergabe erneut aus und vergleichen den Status jedes Frames mit dem Status des goldenen Bildes. Ist dies nicht der Fall, ist der Test fehlgeschlagen.

Während die Vorteile dieser Technik offensichtlich sind, gibt es ein paar Dinge, mit denen Sie vorsichtig sein müssen:

  • Dein Spiel muss deterministisch sein, also musst du vorsichtig sein mit Dingen wie abhängig von deiner Systemuhr, System- / Netzwerkereignissen, Zufallszahlengeneratoren, die nicht deterministisch festgelegt sind. etc.
  • Inhaltsänderungen nach der Erstellung des Golden Image können zu legitimen Unterschieden mit Ihrem Golden Image führen. Daran führt kein Weg vorbei - wenn Sie Ihre Inhalte ändern, müssen Sie Ihr goldenes Image neu generieren.
jpaver
quelle
+1 Es ist auch erwähnenswert, dass der Wert dieses Ansatzes direkt mit der Länge des "goldenen Bildes" zusammenhängt: Wenn er nicht lang genug ist, können Sie leicht Fehler übersehen. Wenn es zu lang ist, werden Sie viel warten müssen. Es ist wichtig, dass Sie versuchen, das Spiel in diesem Modus möglicherweise um eine Größenordnung schneller laufen zu lassen, als Sie es unter normalen Laufzeitbedingungen tun würden, um sich die Zeit zu verkürzen. Das Überspringen des Renderings kann helfen!
Ingenieur
9

Ich stimme den Kommentaren von Jeff und Jpaver zu. Ich wollte auch hinzufügen, dass die Übernahme eines Komponentenmodells für Ihre Architektur die Testbarkeit erheblich verbessert. Bei einem Komponentenmodell sollte jede Komponente eine einzelne Arbeitseinheit ausführen und einzeln (oder mit begrenzten Scheinobjekten) getestet werden können.

Ebenso sollten sich die anderen Teile des Spiels, die auf Entitäten beruhen, nur auf eine Teilmenge der Komponenten stützen, um zu funktionieren. In der Praxis bedeutet dies, dass Sie normalerweise einige gefälschte Komponenten verspotten können, um das Testen dieser Bereiche zu vereinfachen, oder Sie können einfach Teilentitäten zu Testzwecken zusammenstellen. ZB lassen Sie die Rendering- und Eingabekomponenten weg, da diese zum Testen der Physik nicht benötigt werden.

Abschließend möchte ich den Rat bezüglich der Leistung, den Sie von einigen Spielern in Bezug auf Schnittstellen erhalten, ignorieren. Schreiben Sie den Code gut mit Schnittstellen, und wenn Sie später auf Leistungsprobleme stoßen, können Sie das Problem leicht analysieren, identifizieren und umgestalten. Ich war nicht von Noels Bedenken hinsichtlich der Auswirkungen von Schnittstellen auf die Leistung oder des zusätzlichen Komplexitätsaufwands überzeugt.

Das heißt, gehen Sie nicht über Bord und versuchen Sie nicht, jede Kleinigkeit einzeln zu testen. Wie bei den meisten Tests und Designs geht es auch hier darum, die richtige Balance zu finden.

Alex Schearer
quelle
Bitte beachten Sie, dass Sie SX anscheinend nicht neu sind, die Antworten jedoch nicht sortiert sind und das Aussprechen von "beiden oben genannten Kommentaren" schnell veraltet sein wird, da Sie derzeit eine Stimme vor einer Stimme sind der beiden anderen Antworten zu diesem Zeitpunkt. :)
Ricket
Danke, daran habe ich beim Kommentieren nicht gedacht. Ich habe den Kommentar seitdem aktualisiert, um die einzelnen Kommentare herauszusuchen.
Alex Schearer
3

Ich dachte, ich würde eine zweite Antwort hinzufügen, um auf den Kommentar des OP zu antworten, dass Benutzer Komponententests ersetzen könnten. Ich glaube, das ist völlig falsch, da der Zweck von Komponententests nicht darin besteht, die Qualität zu gewährleisten. Wenn Sie Tests durchführen möchten, um die Qualität Ihres Programms sicherzustellen, sollten Sie wahrscheinlich Szenarientests untersuchen oder in eine hervorragende Überwachung investieren.

(Mit einer hervorragenden Überwachung und einem Produkt, das als Dienstleistung ausgeführt wird, ist es in der Tat möglich, einige "Tests" auf den Kunden zu übertragen. Sie benötigen jedoch ein ausgeklügeltes System, das Fehler schnell erkennt und die dafür verantwortlichen Änderungen rückgängig macht. Dies ist höchstwahrscheinlich zu viel ein kleines Entwicklungsteam.)

Der Hauptvorteil von Unit-Tests besteht darin, dass sie den Entwickler dazu zwingen, besser gestalteten Code zu schreiben. Das Testen fordert den Entwickler auf, Bedenken zu trennen und Daten zu kapseln. Außerdem wird der Entwickler ermutigt, Schnittstellen und andere Abstraktionen zu verwenden, um nur eines zu testen.

Alex Schearer
quelle
Stimmen Sie zu, mit der Ausnahme, dass Komponententests Entwickler nicht zwingen, guten Code zu schreiben. Es gibt noch eine andere Möglichkeit: wirklich schlecht geschriebene Tests. Sie müssen sich auf die Idee von Komponententests Ihrer Programmierer einlassen, um zu verhindern, dass sie in die Jahre kommen.
tenpn
2
Klar, aber das ist kein Grund, das Baby mit dem Badewasser rauszuwerfen. Verwenden Sie Werkzeuge verantwortungsbewusst, aber verwenden Sie zuerst die Werkzeuge.
Alex Schearer