Ich habe eine ziemlich große Software, die bestimmte Dateitypen verwendet und sie visualisiert / eine Vielzahl von Schaltflächen zur Bearbeitung des gezeichneten Bildes erstellt. Ich habe das Gefühl, dass ich Fehler / Codeteile finde, die nicht einmal pro Woche funktionieren, aber ich habe Probleme zu verstehen, wie ich Tests für diese Software schreiben kann.
Ich verstehe, wie wichtig Tests für Projekte wie Bibliotheken und APIs sind. Sie schreiben einfach Tests, die diese Funktionen verwenden.
Aber was ist mit Visualisierungssoftware? Aufgrund der visuellen Elemente scheint ein anderer Ansatz erforderlich zu sein.
Muss ich ein Testprogramm oder ein Testkabel schreiben, das jede Operation ausführt und manuell aufruft, sofern ich sie für die Daten verwenden kann?
Welchen Ansatz sollte ich verwenden, um mit dem Schreiben von Tests zu beginnen, um zu überprüfen, ob ich die Fehler behoben habe, und um mich zu benachrichtigen, wenn der Code erneut beschädigt wird?
Es gibt eine ähnliche , aber keine doppelte Frage in Bezug auf, wenn Sie Unit - Tests sollten. Da ich Fehler entdecke, möchte ich Tests schreiben, um zu verhindern, dass sich die Software erneut zurückbildet.
quelle
Alles hat eine Schnittstelle. Wenn ich meinen Testhut aufsetze, verwende ich eine bestimmte Weltanschauung, um einen Test zu schreiben:
In Ihrem Fall besteht Ihr System aus drei Hauptteilen:
Das klingt für mich übrigens sehr nach der ursprünglichen Model-View-Controller-Architektur. Im Idealfall weisen diese drei Elemente eine lose Kopplung auf - das heißt, Sie definieren klare Grenzen zwischen ihnen mit genau definierten (und damit gut testbaren) Schnittstellen.
Eine komplexe Interaktion mit der Software kann in kleine Schritte übersetzt werden, die in Bezug auf die Elemente des Systems, das wir testen, formuliert werden können. Zum Beispiel:
Dies scheint einfach manuell und automatisiert zu testen zu sein. Aber lassen Sie uns diese Geschichte in unser System übersetzen:
Nach Komponenten gruppiert, erhalten wir die folgenden zu testenden Eigenschaften:
Wenn wir das Problem des Testens nicht in kleinere Untertests zerlegen, wird das Testen sehr schwierig und sehr fragil. Die obige Geschichte könnte auch implementiert werden als "Wenn ich eine bestimmte Datei lade und den Schieberegler auf einen bestimmten Wert setze, wird ein bestimmtes Bild gerendert". Dies ist fragil, da es kaputt geht, wenn sich ein Element im System ändert.
Granulare Tests haben auch den großen Vorteil, dass ich das System weiterentwickeln kann, ohne befürchten zu müssen, dass eine Funktion beschädigt wird. Da alle erforderlichen Verhaltensweisen von einer vollständigen Testsuite gemessen werden, werden mich die Tests benachrichtigen, falls etwas kaputt geht. Da sie körnig sind, weisen sie mich auf den Problembereich hin. Wenn ich beispielsweise versehentlich die Schnittstelle einer Komponente ändere, schlagen nur die Tests dieser Schnittstelle fehl und kein anderer Test, der diese Schnittstelle indirekt verwendet.
Wenn das Testen einfach sein soll, erfordert dies ein geeignetes Design. Zum Beispiel ist es problematisch, wenn ich Komponenten in einem System fest verdrahtete: Wenn ich die Interaktion einer Komponente mit anderen Komponenten in einem System testen möchte, muss ich diese anderen Komponenten durch Teststubs ersetzen, mit denen ich protokollieren, überprüfen kann, und choreografiere diese Interaktion. Mit anderen Worten, ich benötige einen Mechanismus zur Abhängigkeitsinjektion, und statische Abhängigkeiten sollten vermieden werden. Beim Testen einer Benutzeroberfläche ist es eine große Hilfe, wenn diese Benutzeroberfläche skriptfähig ist.
Natürlich ist das meiste davon nur eine Fantasie einer idealen Welt, in der alles entkoppelt und leicht zu testen ist und fliegende Einhörner Liebe und Frieden verbreiten ;-) Während alles grundsätzlich testbar ist, ist es oft unerschwinglich schwierig, dies zu tun, und Sie haben es besser Nutzung Ihrer Zeit. Systeme können jedoch auf Testbarkeit ausgelegt werden, und in der Regel verfügen sogar testunabhängige Systeme über interne APIs oder Verträge, die getestet werden können (wenn nicht, wette ich, dass Ihre Architektur Mist ist und Sie einen großen Schlammball geschrieben haben). Nach meiner Erfahrung bewirken bereits geringe Mengen (automatisierter) Tests eine spürbare Qualitätssteigerung.
quelle
Beginnen Sie mit einer bekannten Datei, die ein erwartetes Bild erzeugt. Überprüfen Sie jedes Pixel. Jeder sollte einen erwarteten Wert für eine bekannte, handgefertigte Testdatei haben. Sie sollten ein erwartetes Ausgabebild haben, mit dem Sie es vergleichen können. Alles, was "aus" ist, weist auf einen Fehler in Ihrem Code hin.
Erweitern Sie Ihre Testdatei, damit sich das Ausgabebild ändert und alle Funktionen Ihrer Software erfüllt.
Scripting wäre praktisch für diese Art von Black-Box-Tests. Ein einfaches Skript, das den neuesten Build Ihrer Software für die bekannte Eingabe und erwartete Ausgabe ausführt.
Unit-Tests hingegen sollten White-Box-Tests sein, bei denen Sie den kleinstmöglichen Teil der Software, normalerweise eine Funktion oder was auch immer, verwenden und prüfen, ob sie sich wie erwartet verhält. Sie können sehen, welche Pixelfarbe zurückgegeben wird oder was auch immer. In diesem Fall verhält sich Ihr Code wie eine Bibliothek mit APIs für alle anderen Abschnitte Ihres Codes.
Wenn alles in einer .c-Datei mit allen Funktionen enthalten ist
main()
, haben Sie größere Probleme als beim Testen.quelle