Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

11

08.12.2014, 19:44

Du brauchst nicht jeden moeglichen edge case zu testen meiner Meinung nach.


Also meiner Erfahrung nach sind aber genau Edge Cases die Sachen, die einem am meisten um die Ohren fliegen.
Das man es auch übertreiben kann ist aber wohl wahr.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

12

08.12.2014, 20:07

Also meiner Erfahrung nach sind aber genau Edge Cases die Sachen, die einem am meisten um die Ohren fliegen.
Genau so ist es. Die üblichsten Fälle hat ja man meist bei der Entwicklung schon mal ausprobiert. Aber die Edge Cases nicht. Und da knallt es meist gehörig (fehlende Nullpointer-Checks z.B.).
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (08.12.2014, 20:17)


13

08.12.2014, 21:08

Also ich habe schon von einigen Leuten viel gutes über Unit-Tests gehört, und mich auch schon einige male damit beschäftigt, sie aber letztendlich dann doch nie angewandt. Meiner Meinung nach gibt es einfach in spielen extrem viele Dinge, die extrem schwer durch Unit-Tests abzudecken sind.

Ich meine, so simple Algorithmen oder Funktionen (Kreuzprodukt z.B.) sind meist so simpel, dass man wenig falsch machen kann. Meistens jedoch nimmt man wohl eh ne fertige Implementierung und die stimmt dann eh. Und für viele andere Dinge hat man dann sehr sehr schnell so komplizierte Testfälle, dass ich persönlich dafür keinen Test schreiben will. Man kann eben einfach nicht jede Funktion getrennt betrachten, ein paar Eingabewerte reinschmeißen und gucken ob das Ergebnis stimmt.
Nehmen wir die Kollisionsabfrage: Man hat ein Terrain als Heightmapt, generiert daraus Dreiecke, repräsentiert den Spieler durch eine Kugel oder Zylinder und will gucken, ob die Kollisionsabfrage passt. Viel Spaß beim Ausrechnen der Testdaten. Alternative: Man baut in sein Programm schnell ne Debuganzeige ein und testet es gerade durch.
Oder nehmen wir die KI: Computergegner sollen auf das reagieren, was der Spieler macht. Wird auch sicherlich spaßig, wenn man einen kompletten Spielablauf simulieren will. Natürlich kann man auch einfach gucken, bei welchen Werten ein interne KI-Zustand umgeschaltet wird und gezielt solche Werte oben reinschmeißen. Damit testet man dann aber nicht mehr die KI, sondern guckt, ob die if-Abfrage funktioniert. Und das tut sie halt immer...

Tests mögen gut sein, wenn man wenig Eingabewerte, wenig Ausgabewerte und eine komplexe Logik dazwischen hat. Und eine gute Möglichkeit, Testfälle zu generieren.

Anders sieht es halt aus, wenn man Python oder PHP programmiert. Wenn C++ kompiliert wird, wird ja schon eine Art statische Code-Analyse betrieben, ein syntaktisch korrektes Programm kann schonmal einen riesigen Haufen Blödsinn nicht mehr machen (Variablen benutzen die nicht existieren, z.B.). In Python kann es halt passieren, dass dein Programm jahrelang ohne Probleme läuft und dann einmal ein seletenes Code-Fragment ausgeführt wird, in dem ein Syntax-Fehler ist. Ist dann oft trivial zu beheben, aber man muss eben wirklich jeden Programmpfad irgendwie testen, um alle derartigen Fehler zu finden.
Wenn man sich in C++ dagegen etwas mühe gibt (RAII, const-correctness, keine manuelle Speicherverwaltung, Exceptions statt Rückgabewerte die jeder vergisst zu testen) kann man meiner Meinung nach schon sehr sehr robuste Programme schreiben, bei denen viele Dinge die man sonst mit Unit-Test überprüfen würde, gar nicht erst auftreten.
Ich würde daher lieber mehr Zeit in ein sauberes und robustes Design stecken, als unnötige Unit-Test zu schreiben, nur weil sie gerade in sind (ich will nicht sagen, dass alle Unit-Test unnötig sind, aber wenn man einfach welche schreibt, um Unit-Test zu haben weil Unit-Test ja toll sind, wird gerade jemand mit wenig Erfahrung vermutlich haufenweise überflüssige Tests schreiben, und sich dann einen Ast freuen, weil er weiß, dass seine Matrizenaddition nach 6 Monaten immer noch assoziativ ist...)
Lieber dumm fragen, als dumm bleiben!

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

14

08.12.2014, 21:27

Falls du deine Matrizenaddition irgendwann mal mit AVX umsetzt wirst du dich wahrscheinlich freuen gleich ein paar vernünftige Tests parat zu haben ...

Wenn sich dein Code nie ändert wird, wird wahrscheinlich selten ein Test mal fehlschlagen. Ich geh mittlerweile aber eher davon aus, das jeder Code irgendwann mal gewartet wird.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

Tobiking

1x Rätselkönig

  • Private Nachricht senden

15

09.12.2014, 01:24

Ich meine, so simple Algorithmen oder Funktionen (Kreuzprodukt z.B.) sind meist so simpel, dass man wenig falsch machen kann. Meistens jedoch nimmt man wohl eh ne fertige Implementierung und die stimmt dann eh.

Wenn du der fertigen Implementierung traust, brauchst du diese natürlich nicht zu testen. Wenn aber später deine KI nicht das tut was sie soll, und es dann letztendlich am falschen Kreuzprodukt liegt, während du an der falschen Stelle suchst, wirst du dich ärgern. Und wie schon erwähnt wurde, wenn du die Implementierung tauscht (Neue Version, Optimierung oder Portierung auf anderes System) bist du froh, wenn du ein Indiz hast, dass diese sich grundsätzlich gleich verhält.


Nehmen wir die Kollisionsabfrage: Man hat ein Terrain als Heightmapt, generiert daraus Dreiecke, repräsentiert den Spieler durch eine Kugel oder Zylinder und will gucken, ob die Kollisionsabfrage passt. Viel Spaß beim Ausrechnen der Testdaten. Alternative: Man baut in sein Programm schnell ne Debuganzeige ein und testet es gerade durch.

Ich sehe nicht wo das Problem hier sein soll. Die Kollisionsabfrage wird wohl eine Reihe von Objekte (als Menge von Dreiecken) auf Kollision prüfen. Also lade ich je eine Szene wo die Objekte kollidieren, sich berühren und getrennt voneinander sind. Dann frage ich das Ergebnis der Kollisionsprüfung ab und kontrolliere es mit dem was es sein soll. Ich habe hier natürlich die Abhängigkeit zum Level-Loader. Aber wenn ich für diesen separate Tests habe, erkenne ich das es sich um Folgefehler handelt.


Oder nehmen wir die KI: Computergegner sollen auf das reagieren, was der Spieler macht. Wird auch sicherlich spaßig, wenn man einen kompletten Spielablauf simulieren will. Natürlich kann man auch einfach gucken, bei welchen Werten ein interne KI-Zustand umgeschaltet wird und gezielt solche Werte oben reinschmeißen. Damit testet man dann aber nicht mehr die KI, sondern guckt, ob die if-Abfrage funktioniert. Und das tut sie halt immer...

Einen Zustandsübergang würde ich nicht testen. Von einem KI Modul würde ich auch eher erwarten, dass es eine Situation (Umgebung + Positionen Spieler und eigene) übergeben bekommt und eine Aktion (z.B. Laufe + Router) zurückgibt. Das kann ich testen.


Tests mögen gut sein, wenn man wenig Eingabewerte, wenig Ausgabewerte und eine komplexe Logik dazwischen hat. Und eine gute Möglichkeit, Testfälle zu generieren.

Ich glaube du erwartest zu viel bzw. das falsche von Unit Tests. Sie sollen die Qualität der Software erhöhen, indem sie den Entwickler unterstützen Fehler zu finden. Sie sollen nicht bescheinigen das eine Software fehlerfrei ist. Das ist praktisch unmöglich. Deswegen braucht man auch nicht so unglaublich viele Testfälle.

Ich würde daher lieber mehr Zeit in ein sauberes und robustes Design stecken, als unnötige Unit-Test zu schreiben, nur weil sie gerade in sind (ich will nicht sagen, dass alle Unit-Test unnötig sind, aber wenn man einfach welche schreibt, um Unit-Test zu haben weil Unit-Test ja toll sind, wird gerade jemand mit wenig Erfahrung vermutlich haufenweise überflüssige Tests schreiben, und sich dann einen Ast freuen, weil er weiß, dass seine Matrizenaddition nach 6 Monaten immer noch assoziativ ist...)

Unit Tests bilden eine ziemlich gute Synergie zum guten Design, da es ein gutes Design braucht um Unit Tests schreiben zu können. Außerdem kann man beim Refactoring meist schnell sehen wenn was kaputt geht. Und als Dokumentation dienen sie auch. Immerhin zeigen sie Beispielhaft wie ein Modul verwendet wird.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

16

09.12.2014, 06:43

Testautomatisierung wird bei uns schon aus einem massiv wichtigen Grund eingesetzt: Regression. Die meisten Fehler passieren nicht, wenn man zum ersten Mal etwas implementiert. Da testet man ja manuell eigentlich ausführlich. Sie entstehen, wenn man mal irgendwo irgendwas umbaut. Da hat man dann oft irgendwas nicht bedacht und schon ist der Bug entstanden. Ein automatischer Test findet solche Fehler sehr oft
Unit-Tests sind auch für Spiele problemlos möglich. Kompliziert wird es erst bei Modul-Tests und bei Tests, die Renderings überprüfen sollen. Bei Standbildern mag das noch gehen, aber sieht irgendein animierter Shader oder eine Animation richtig aus? Das sind dann typische Fälle für regelmäßige manuelle Tests nach festgeschriebenen Test-Abläufen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

17

09.12.2014, 09:35

Nehmen wir die Kollisionsabfrage: Man hat ein Terrain als Heightmapt, generiert daraus Dreiecke, repräsentiert den Spieler durch eine Kugel oder Zylinder und will gucken, ob die Kollisionsabfrage passt. Viel Spaß beim Ausrechnen der Testdaten. Alternative: Man baut in sein Programm schnell ne Debuganzeige ein und testet es gerade durch.

Ich bin gerade dabei eine (primitive, auf diskreter Bewegung auf einem 2D Grid basierende) Physik zu implementieren. Dabei baue ich die API so, dass ich sie eben (a) gut testen und (b) modular verwenden kann. Konkret heißt das z.B.

C-/C++-Quelltext

1
bool ObjectPhysics::doesCollide(GameObject const & other) { // ...

(Wie angedeutet/gesagt: ObjectPhysics ist eine ObjectComponent und damit Teil eines GameObjects). D.h. zum Testen erzeuge ich mir zwei GameObjects mit Physics-Komponente und spiele eben verschiedene Fälle (inkl. Edge Cases!) durch, d.h. ich positioniere die GameObjects, gebe ihnen verschiedene Kollisionsflags (so dass z.B. ein Feuerball mit einem Spieler, aber nicht mit einer Gegnerleiche kollidieren kann) und arbeite diese Fälle durch.
Und die Verwendung der Physics-Komponente läuft dann analog: Die Spiellogik gibt ein Szenario vor und die Physik soll die Frage der Kollision beantworten.

Das Interessante: Wenn ich meine Kollision irgendwann nicht mehr so primitiv haben will, ändere ich die Implementierung und freue mich, wenn die Testcases sagen: "Jup, das passt" - oder ich weiß eben was entgegen der ursprünglichen Implementierung nun nicht mehr läuft. Finde ich den Fehler im Spielfluss, dann kann ich nicht ohne weiteres sagen, dass das Objekt jetzt in dem anderen steht weil die Physik es versaut hat - vllt. ist es auch nur ein Rendering-Fehler (weil ich die Implementierung inzwischen geändert habe).

Oder nehmen wir die KI: Computergegner sollen auf das reagieren, was der Spieler macht. Wird auch sicherlich spaßig, wenn man einen kompletten Spielablauf simulieren will. Natürlich kann man auch einfach gucken, bei welchen Werten ein interne KI-Zustand umgeschaltet wird und gezielt solche Werte oben reinschmeißen. Damit testet man dann aber nicht mehr die KI, sondern guckt, ob die if-Abfrage funktioniert. Und das tut sie halt immer...

Wie BlueCobold schon erwähnt hat: Problematisch sind Tests nach Codeänderungen - initiale Implementierungen arbeiten meist richtig ^^
Und auch hier werde ich (sobald ich den KI-Kram neu implementiere) eine analoge Vorgehensweise fahren, wie bei der Physik, z.B.

C-/C++-Quelltext

1
2
// würde einen non-owning pointer oder ggf. nullptr liefern - je nach dem ob ein Ziel gefunden wurde
GameObject* ObjectAi::searchNextEnemy() { // ...

um eben zu erreichen (a) die API ist testbar und (b) die API ist modular verwendbar (gut, die Reihenfolge sollte wie auch oben schon genau anders rum sein - aber das ist ja erstmal egal ^^). Dann kann ich testen: Ich gebe ein Szenario vor mit 0, 1, 2, n GameObjekten in Reichweite (dabei ist dann klar welches gefunden werden sollte) und prüfe ob die KI auch das erwartete Ergebnis liefert. Spätestens wenn ich die Implementierung optimieren/modifizieren will, habe ich den zeitlichen Aufwand zum Schreiben der Testfälle wieder - ich will mich nicht gedanklich nochmal durch das Programm hangeln müssen und mir überlegen "ok, bei 2 Objekten..." - vor allem nicht, wenn der Code später irgendwie von mir optimiert wurde :S

und sich dann einen Ast freuen, weil er weiß, dass seine Matrizenaddition nach 6 Monaten immer noch assoziativ ist...

Wenn die Addition in den 6 Monaten geändert wurde, dann kann man sich ja einen Ast freuen :thumbup:

Aber klar ist: Manche Sachen lassen sich einfacher testen, andere schwerer. Ich denke das gilt nicht nur für die Spieleentwicklung :P

LG Glocke

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

18

09.12.2014, 11:19

Das gilt in der Tat nicht nur für die Spielentwicklung.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

19

09.12.2014, 12:19

Was wären denn so Best Practices der TDD?
  • Kleine, übersichtliche, inhaltlich kohärente Testcases
  • ...?
Vielleicht bekommen wir ja eine hilfreiche Liste für's Wiki zusammen :)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

20

09.12.2014, 12:22

http://en.wikipedia.org/wiki/Test-driven_development
Mehr gibt's dazu nicht zu sagen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige