it-swarm.com.de

kontinuierliche Integration für wissenschaftliche Software

Ich bin kein Softwareentwickler. Ich bin Doktorand auf dem Gebiet der Geowissenschaften.

Vor fast zwei Jahren begann ich eine wissenschaftliche Software zu programmieren. Ich habe nie Continuous Integration (CI) verwendet, hauptsächlich, weil ich zunächst nicht wusste, dass es existiert und ich die einzige Person war, die an dieser Software arbeitete.

Jetzt, da die Basis der Software läuft, beginnen sich andere Leute dafür zu interessieren und möchten einen Beitrag zur Software leisten. Es ist geplant, dass andere Personen an anderen Universitäten Ergänzungen zur Kernsoftware implementieren. (Ich habe Angst, sie könnten Fehler einführen). Außerdem wurde die Software ziemlich komplex und immer schwieriger zu testen, und ich plane auch, weiter daran zu arbeiten.

Aus diesen beiden Gründen denke ich jetzt immer mehr über die Verwendung von CI nach. Da ich nie eine Ausbildung zum Software-Ingenieur hatte und niemand in meiner Umgebung jemals von CI gehört hat (wir sind Wissenschaftler, keine Programmierer), fällt es mir schwer, mit meinem Projekt zu beginnen.

Ich habe ein paar Fragen, bei denen ich einen Rat erhalten möchte:

Zunächst eine kurze Erklärung der Funktionsweise der Software:

  • Die Software wird von einer XML-Datei gesteuert, die alle erforderlichen Einstellungen enthält. Sie starten die Software, indem Sie einfach den Pfad zur XML-Datei als Eingabeargument übergeben. Sie wird ausgeführt und erstellt einige Dateien mit den Ergebnissen. Ein einzelner Lauf kann ~ 30 Sekunden dauern.

  • Es ist eine wissenschaftliche Software. Fast alle Funktionen haben mehrere Eingabeparameter, deren Typen meist recht komplexe Klassen sind. Ich habe mehrere TXT-Dateien mit großen Katalogen, mit denen Instanzen dieser Klassen erstellt werden.

Kommen wir nun zu meinen Fragen:

  1. Unit-Tests, Integrationstests, End-to-End-Tests? : Meine Software umfasst jetzt etwa 30.000 Codezeilen mit Hunderten von Funktionen und ~ 80 Klassen. Es kommt mir komisch vor, Unit-Tests für Hunderte von Funktionen zu schreiben, die bereits implementiert sind. Also habe ich darüber nachgedacht, einfach einige Testfälle zu erstellen. Bereiten Sie 10-20 verschiedene XML-Dateien vor und lassen Sie die Software laufen. Ich denke, das nennt man End-to-End-Tests? Ich habe oft gelesen, dass Sie dies nicht tun sollten, aber vielleicht ist es zunächst in Ordnung, wenn Sie bereits eine funktionierende Software haben? Oder ist es einfach eine blöde Idee, CI zu einer bereits funktionierenden Software hinzuzufügen.

  2. Wie schreibt man Unit-Tests, wenn die Funktionsparameter schwer zu erstellen sind? Angenommen, ich habe eine Funktion double fun(vector<Class_A> a, vector<Class_B>) und normalerweise würde ich Sie müssen zuerst mehrere Textdateien einlesen, um Objekte vom Typ Class_A und Class_B zu erstellen. Ich dachte darüber nach, einige Dummy-Funktionen wie Class_A create_dummy_object() zu erstellen, ohne die Textdateien einzulesen. Ich habe auch darüber nachgedacht, eine Art Serialisierung zu implementieren. (Ich habe nicht vor, die Erstellung der Klassenobjekte zu testen, da sie nur von mehreren Textdateien abhängen.)

  3. Wie schreibe ich Tests, wenn die Ergebnisse sehr unterschiedlich sind? Meine Software verwendet große Monte-Carlo-Simulationen und arbeitet iterativ. Normalerweise haben Sie ~ 1000 Iterationen und bei jeder Iteration erstellen Sie ~ 500-20.000 Instanzen von Objekten basierend auf Monte-Carlo-Simulationen. Wenn nur ein Ergebnis einer Iteration etwas anders ist, sind die gesamten bevorstehenden Iterationen völlig unterschiedlich. Wie gehen Sie mit dieser Situation um? Ich denke, dies ist ein großer Punkt gegen End-to-End-Tests, da das Endergebnis sehr unterschiedlich ist.

Jeder andere Rat bei CI wird sehr geschätzt.

22
user7431005

Das Testen von wissenschaftlicher Software ist schwierig, sowohl aufgrund des komplexen Themas als auch aufgrund typischer wissenschaftlicher Entwicklungsprozesse (auch bekannt als "Hack it", bis es funktioniert, was normalerweise nicht zu einem testbaren Design führt). Dies ist etwas ironisch, wenn man bedenkt, dass Wissenschaft reproduzierbar sein sollte. Was sich im Vergleich zu „normaler“ Software ändert, ist nicht, ob Tests nützlich sind (ja!), Sondern welche Testarten geeignet sind.

mgang mit Zufälligkeit : Alle Läufe Ihrer Software MÜSSEN reproduzierbar sein. Wenn Sie Monte-Carlo-Techniken verwenden, müssen Sie es ermöglichen, einen bestimmten Startwert für den Zufallszahlengenerator bereitzustellen.

  • Es ist leicht, dies zu vergessen, z. bei Verwendung der Funktion Rand() von C, die vom globalen Status abhängt.
  • Im Idealfall wird ein Zufallszahlengenerator als explizites Objekt durch Ihre Funktionen übergeben. Der Standardbibliotheksheader random von C++ 11 erleichtert dies erheblich.
  • Anstatt den Zufallsstatus zwischen den Modulen der Software zu teilen, fand ich es nützlich, ein zweites RNG zu erstellen, das durch eine Zufallszahl aus dem ersten RNG gesetzt wird. Wenn sich dann die Anzahl der Anforderungen an das RNG durch das andere Modul ändert, bleibt die vom ersten RNG erzeugte Sequenz gleich.

Integrationstests sind vollkommen in Ordnung. Sie können gut überprüfen, ob verschiedene Teile Ihrer Software korrekt zusammenspielen, und konkrete Szenarien ausführen.

  • Als Mindestqualitätsstufe kann „es stürzt nicht ab“ bereits ein gutes Testergebnis sein.
  • Um bessere Ergebnisse zu erzielen, müssen Sie die Ergebnisse auch anhand einer Basislinie überprüfen. Diese Überprüfungen müssen jedoch etwas tolerant sein, z. Rundungsfehler berücksichtigen. Es kann auch hilfreich sein, zusammenfassende Statistiken anstelle vollständiger Datenzeilen zu vergleichen.
  • Wenn die Überprüfung anhand einer Basislinie zu fragil wäre, überprüfen Sie, ob die Ausgaben gültig sind und einige allgemeine Eigenschaften erfüllen. Diese können allgemein ("ausgewählte Standorte müssen mindestens 2 km voneinander entfernt sein") oder szenariospezifisch sein, z. "Ein ausgewählter Ort muss sich in diesem Bereich befinden".

Wenn Sie Integrationstests ausführen, empfiehlt es sich, einen Testläufer als separates Programm oder Skript zu schreiben. Dieser Testläufer führt die erforderlichen Einstellungen durch, führt die zu testende ausführbare Datei aus, überprüft alle Ergebnisse und bereinigt anschließend.

nit Test Stilprüfungen können sehr schwierig in wissenschaftliche Software einzufügen sein, da die Software nicht dafür entwickelt wurde. Insbesondere Unit-Tests werden schwierig, wenn das zu testende System viele externe Abhängigkeiten/Interaktionen aufweist. Wenn die Software nicht rein objektorientiert ist, ist es im Allgemeinen nicht möglich, diese Abhängigkeiten zu verspotten/zu stubben. Ich habe festgestellt, dass es am besten ist, Komponententests für solche Software weitgehend zu vermeiden, mit Ausnahme von reinen mathematischen Funktionen und Dienstprogrammfunktionen.

Selbst ein paar Tests sind besser als keine Tests. In Kombination mit der Prüfung „Es muss kompiliert werden“ ist dies bereits ein guter Anfang für die kontinuierliche Integration. Sie können jederzeit zurückkehren und später weitere Tests hinzufügen. Sie können dann Bereiche des Codes priorisieren, die mit größerer Wahrscheinlichkeit beschädigt werden, z. weil sie mehr Entwicklungsaktivität bekommen. Um festzustellen, welche Teile Ihres Codes nicht durch Komponententests abgedeckt sind, können Sie Tools zur Codeabdeckung verwenden.

Manuelles Testen : Insbesondere bei komplexen Problembereichen können Sie nicht alles automatisch testen. Z.B. Ich arbeite derzeit an einem stochastischen Suchproblem. Wenn ich teste, dass meine Software immer das gleiche Ergebnis liefert, kann ich es nicht verbessern, ohne die Tests zu unterbrechen. Stattdessen habe ich es einfacher gemacht, manuelle Tests durchzuführen: Ich führe die Software mit einem festen Startwert aus und erhalte einen ) Visualisierung des Ergebnisses (abhängig von Ihren Vorlieben erleichtern R, Python/Pyplot und Matlab das Abrufen hochwertiger Visualisierungen Ihrer Datensätze). Ich kann diese Visualisierung verwenden, um zu überprüfen, ob die Dinge nicht schrecklich schief gelaufen sind. Ebenso kann das Verfolgen des Fortschritts Ihrer Software über die Protokollierungsausgabe eine praktikable manuelle Testmethode sein, zumindest wenn ich die Art der zu protokollierenden Ereignisse auswählen kann.

23
amon

Es kommt mir komisch vor, Unit-Tests für Hunderte von Funktionen zu schreiben, die bereits implementiert sind.

Sie möchten (normalerweise) die Tests schreiben, während Sie die genannten Funktionen ändern . Sie müssen sich nicht zurücklehnen und Hunderte von Komponententests für die vorhandenen Funktionen schreiben, das wäre (größtenteils) Zeitverschwendung. Die Software funktioniert (wahrscheinlich) einwandfrei. Mit diesen Tests soll sichergestellt werden, dass zukünftige Änderungen nicht das alte Verhalten beeinträchtigen. Wenn Sie eine bestimmte Funktion nie wieder ändern, lohnt es sich wahrscheinlich nie, sich die Zeit zum Testen zu nehmen (da sie derzeit funktioniert, immer funktioniert hat und wahrscheinlich weiterhin funktioniert). Ich empfehle, Effektiv mit Legacy-Code arbeiten von Michael Feathers an dieser Front zu lesen. Er verfügt über einige großartige allgemeine Strategien zum Testen bereits vorhandener Dinge, einschließlich Techniken zum Aufbrechen von Abhängigkeiten, Charakterisierungstests (Ausgabe der Kopier-/Einfügefunktion in die Testsuite, um sicherzustellen, dass Sie das Regressionsverhalten beibehalten) und vieles mehr.

Wie schreibt man Unit-Tests, wenn die Funktionsparameter schwer zu erstellen sind?

Idealerweise nicht. Stattdessen vereinfachen Sie das Erstellen der Parameter (und damit das Testen Ihres Designs). Zugegeben, Designänderungen brauchen Zeit, und diese Refactorings können bei älteren Projekten wie Ihrem schwierig sein. TDD (Test Driven Development) kann dabei helfen. Wenn die Parameter sehr schwer zu erstellen sind, haben Sie große Probleme beim Schreiben von Tests im Test-First-Stil.

Verwenden Sie kurzfristig Mocks, aber hüten Sie sich davor, die Hölle und die damit verbundenen Probleme zu verspotten. Als ich als Softwareentwickler gewachsen bin, habe ich Mocks erkannt sind fast immer ein Mini-Geruch, der versucht, ein größeres Problem zu lösen und das Kernproblem nicht anzusprechen. Ich bezeichne es gerne als "Trottelverpackung", denn wenn Sie ein Stück Alufolie auf ein Stück Hundekot auf Ihrem Teppich legen, stinkt es immer noch. Was Sie tun müssen, ist tatsächlich aufzustehen, die Kacke zu schöpfen, sie in den Müll zu werfen und dann den Müll herauszunehmen. Dies ist offensichtlich mehr Arbeit, und Sie riskieren, Fäkalien in Ihre Hände zu bekommen, aber auf lange Sicht besser für Sie und Ihre Gesundheit. Wenn Sie diese Kacke immer wieder einpacken, möchten Sie nicht mehr lange in Ihrem Haus leben. Mocks sind von Natur aus ähnlich.

Wenn Sie beispielsweise Ihren Class_A Haben, der schwer zu instanziieren ist, weil Sie 700 Dateien einlesen müssen, können Sie ihn einfach verspotten. Das nächste, was Sie wissen, ist, dass Ihr Mock veraltet ist und der echte Class_A Etwas ganz anderes macht als der Mock , und Ihre Tests bestehen immer noch, obwohl sie fehlschlagen sollten. Eine bessere Lösung besteht darin, Class_A aufzuschlüsseln. in einfacher zu verwendende/testende Komponenten und testen Sie stattdessen diese Komponenten. Schreiben Sie möglicherweise einen Integrationstest, der tatsächlich auf die Festplatte trifft, und stellen Sie sicher, dass Class_A Als Ganzes funktioniert. Oder haben Sie einfach einen Konstruktor für Class_A, Den Sie mit einer einfachen Zeichenfolge (die Ihre Daten darstellt) instanziieren können, anstatt von der Festplatte lesen zu müssen.

Wie schreibe ich Tests, wenn die Ergebnisse sehr unterschiedlich sind?

Ein paar Tipps:

1) Verwenden Sie Inverse (oder allgemeiner Eigenschaften-basierte Tests). Was ist der Effekt von [1,2,3,4,5]? Keine Ahnung. Was ist ifft(fft([1,2,3,4,5]))? Sollte [1,2,3,4,5] Sein (oder in der Nähe davon, können Gleitkommafehler auftreten).

2) Verwenden Sie "bekannte" Asserts. Wenn Sie eine Determinantenfunktion schreiben, kann es schwierig sein zu sagen, was die Determinante einer 100x100-Matrix ist. Sie wissen jedoch, dass die Determinante der Identitätsmatrix 1 ist, selbst wenn sie 100 x 100 beträgt. Sie wissen auch, dass die Funktion in einer nicht invertierbaren Matrix 0 zurückgeben sollte (wie 100x100 mit allen Nullen).

3) Verwenden Sie grobe Asserts anstelle von exakten Asserts. Ich habe vor einiger Zeit einen Code geschrieben, der zwei Bilder von registriert hat Generieren von Verbindungspunkten, die eine Zuordnung zwischen den Bildern erstellen, und Verziehen zwischen ihnen, damit sie übereinstimmen. Es könnte sich auf einer Subpixel-Ebene registrieren. Wie können Sie es testen? Dinge wie:

EXPECT_TRUE(reg(img1, img2).size() < min(img1.size(), img2.size()))

da Sie sich nur für überlappende Teile registrieren können, muss das registrierte Bild kleiner oder gleich Ihrem kleinsten Bild sein. Außerdem:

scale = 255
EXPECT_PIXEL_EQ_WITH_TOLERANCE(reg(img, img), img, .05*scale)

da ein für sich selbst registriertes Bild in der Nähe von sich selbst sein sollte, es jedoch aufgrund des vorliegenden Algorithmus möglicherweise zu mehr als Gleitkommafehlern kommt, überprüfen Sie einfach, ob jedes Pixel +/- 5% des gültigen Bereichs (0-255) beträgt ist ein allgemeiner Bereich (Graustufen). Sollte mindestens gleich groß sein. Sie können sogar einfach Rauchtest (d. H. Rufen Sie es an und stellen Sie sicher, dass es nicht abstürzt). Im Allgemeinen ist diese Technik besser für größere Tests geeignet, bei denen das Endergebnis nicht (einfach) a priori vor dem Ausführen des Tests berechnet werden kann.

4) Verwenden Sie OR SPEICHERN Sie einen Zufallszahlen-Startwert für Ihr RNG.

Runs do müssen reproduzierbar sein. Es ist jedoch falsch, dass der einzige Weg, einen reproduzierbaren Lauf zu erhalten, darin besteht, einem Zufallszahlengenerator einen spezifischen Startwert bereitzustellen. Manchmal ist eine Zufallsprüfung wertvoll . Ich habe Fehler im wissenschaftlichen Code gesehen, die in entarteten Fällen auftreten, die zufällig generiert wurden. Anstatt immer Ihre Funktion mit demselben Startwert aufzurufen, generieren Sie einen Zufall Samen, und verwenden Sie dann diesen Samen und protokollieren Sie den Wert des Samens. Auf diese Weise hat jeder Lauf einen anderen zufälligen Startwert. Wenn Sie jedoch abstürzen, können Sie das Ergebnis mithilfe des von Ihnen protokollierten Startwerts erneut ausführen zu debuggen. Ich habe dies tatsächlich in der Praxis verwendet und es hat einen Fehler beseitigt, also dachte ich, ich würde es erwähnen. Nachteil: Sie müssen Ihre Testläufe protokollieren. Oben: Korrektheit und Bug Nuking.

HTH.

7
  1. Arten von Tests

    • Es kommt mir komisch vor, Unit-Tests für Hunderte von Funktionen zu schreiben, die bereits implementiert sind

      Stellen Sie sich das anders herum vor: Wenn ein Patch, der mehrere Funktionen berührt, einen Ihrer End-to-End-Tests unterbricht, wie können Sie dann herausfinden, welches das Problem ist?

      Es ist viel einfacher Unit-Tests für einzelne Funktionen zu schreiben als für das gesamte Programm. Es ist viel einfacher, um sicherzugehen, dass Sie eine einzelne Funktion gut abdecken. Es ist viel einfacher, eine Funktion umzugestalten, wenn Sie sicher sind, dass die Komponententests alle Eckfälle erfassen, die Sie gebrochen haben.

      Das Schreiben von Komponententests für bereits vorhandene Funktionen ist für jeden, der an einer Legacy-Codebasis gearbeitet hat, völlig normal. Sie sind eine gute Möglichkeit, Ihr Verständnis der Funktionen zu bestätigen, und sobald sie geschrieben sind, sind sie eine gute Möglichkeit, unerwartete Verhaltensänderungen zu finden.

    • End-to-End-Tests lohnen sich ebenfalls. Wenn sie einfacher zu schreiben sind, führen Sie diese auf jeden Fall zuerst durch und fügen Sie Ad-hoc-Komponententests hinzu, um die Funktionen abzudecken, die Sie am meisten über das Brechen anderer beunruhigen. Sie müssen nicht alles auf einmal tun.

    • Ja, das Hinzufügen von CI zu vorhandener Software ist sinnvoll und normal.

  2. Wie schreibe ich Unit-Tests

    Wenn Ihre Objekte sehr teuer und/oder komplex sind, schreiben Sie Mocks. Sie können die Tests einfach mithilfe von Mocks getrennt von den Tests mit realen Objekten verknüpfen, anstatt Polymorphismus zu verwenden.

    Sie sollten auf jeden Fall eine einfache Möglichkeit zum Erstellen von Instanzen haben - eine Funktion zum Erstellen von Dummy-Instanzen ist üblich -, aber es ist auch sinnvoll, Tests für den tatsächlichen Erstellungsprozess durchzuführen.

  3. Variable Ergebnisse

    Sie müssen einige Invarianten für das Ergebnis haben. Testen Sie diese anstelle eines einzelnen numerischen Werts.

    Sie könnten einen Schein-Pseudozufallszahlengenerator bereitstellen, wenn Ihr Monte-Carlo-Code ihn als Parameter akzeptiert, wodurch die Ergebnisse zumindest für einen bekannten Algorithmus vorhersehbar wären. Er ist jedoch spröde, es sei denn, er gibt buchstäblich jedes Mal dieselbe Zahl zurück.

2
Useless

In einer Antwort vor erwähnte amon bereits einige sehr wichtige Punkte. Lassen Sie mich noch etwas hinzufügen:

1. Unterschiede zwischen der Entwicklung von wissenschaftlicher Software und kommerzieller Software

Bei wissenschaftlicher Software liegt der Schwerpunkt normalerweise natürlich auf dem wissenschaftlichen Problem. Die Probleme bestehen eher darin, den theoretischen Hintergrund zu behandeln, die beste numerische Methode zu finden usw. Die Software ist nur ein mehr oder weniger kleiner Teil der Arbeit.

Die Software wird in den meisten Fällen von einer oder nur wenigen Personen geschrieben. Es wird oft für ein bestimmtes Projekt geschrieben. Wenn das Projekt abgeschlossen ist und alles veröffentlicht ist, wird die Software in vielen Fällen nicht mehr benötigt.

Kommerzielle Software wird normalerweise von großen Teams über einen längeren Zeitraum entwickelt. Dies erfordert viel Planung für Architektur, Design, Komponententests, Integrationstests usw. Diese Planung erfordert eine erhebliche Menge an Zeit und Erfahrung. In einem wissenschaftlichen Umfeld ist normalerweise keine Zeit dafür.

Wenn Sie Ihr Projekt in eine Software konvertieren möchten, die kommerzieller Software ähnelt, sollten Sie Folgendes überprüfen:

  • Haben Sie Zeit und Ressourcen?
  • Was ist die langfristige Perspektive der Software? Was passiert mit der Software, wenn Sie Ihre Arbeit beenden und die Universität verlassen?

2. End-to-End-Tests

Wenn die Software immer komplexer wird und mehrere Personen daran arbeiten, sind Tests obligatorisch. Aber wie bereits erwähnt amon , ist es ziemlich schwierig, Unit-Tests zu wissenschaftlicher Software hinzuzufügen. Sie müssen also einen anderen Ansatz verwenden.

Da Ihre Software wie die meisten wissenschaftlichen Programme ihre Eingabe aus einer Datei erhält, eignet sie sich perfekt zum Erstellen mehrerer Beispiel-Eingabe- und Ausgabedateien. Sie sollten diese Tests bei jeder Version automatisch ausführen und die Ergebnisse mit Ihren Proben vergleichen. Dies könnte ein sehr guter Ersatz für Unit-Tests sein. Auf diese Weise erhalten Sie auch Integrationstests.

Um reproduzierbare Ergebnisse zu erhalten, sollten Sie natürlich denselben Startwert für Ihren Zufallszahlengenerator verwenden, den amon bereits geschrieben hat.

Die Beispiele sollten typische Ergebnisse Ihrer Software abdecken. Dies sollte auch Edge-Fälle Ihres Parameterraums und numerische Algorithmen umfassen.

Sie sollten versuchen, Beispiele zu finden, die nicht zu viel Zeit zum Ausführen benötigen, aber dennoch typische Testfälle abdecken.

3. Kontinuierliche Integration

Da das Ausführen der Testbeispiele einige Zeit in Anspruch nehmen kann, denke ich, dass eine kontinuierliche Integration nicht möglich ist. Sie müssen die zusätzlichen Teile wahrscheinlich mit Ihren Kollegen besprechen. Zum Beispiel müssen sie mit den verwendeten numerischen Methoden übereinstimmen.

Daher denke ich, dass es besser ist, die Integration auf eine genau definierte Weise durchzuführen, nachdem der theoretische Hintergrund und die numerischen Methoden, sorgfältige Tests usw. besprochen wurden.

Ich halte es nicht für eine gute Idee, eine Art Automatismus für die kontinuierliche Integration zu haben.

Verwenden Sie übrigens ein Versionskontrollsystem?

4. Testen Sie Ihre numerischen Algorithmen

Wenn Sie numerische Ergebnisse vergleichen, z. Wenn Sie Ihre Testausgaben überprüfen, sollten Sie keine schwebenden Zahlen auf Gleichheit prüfen. Es kann immer Rundungsfehler geben. Überprüfen Sie stattdessen, ob die Differenz unter einem bestimmten Schwellenwert liegt.

Es ist auch eine gute Idee, Ihre Algorithmen mit verschiedenen Algorithmen zu vergleichen oder das wissenschaftliche Problem auf andere Weise zu formulieren und die Ergebnisse zu vergleichen. Wenn Sie dieselben Ergebnisse auf zwei oder mehr unabhängige Arten erzielen, ist dies ein guter Hinweis darauf, dass Ihre Theorie und Ihre Implementierung korrekt sind.

Sie können diese Tests in Ihrem Testcode durchführen und den schnellsten Algorithmus für Ihren Produktionscode verwenden.

1
bernie
  1. Es ist niemals eine blöde Idee, CI hinzuzufügen. Aus Erfahrung weiß ich, dass dies der richtige Weg ist, wenn Sie ein Open-Source-Projekt haben, bei dem die Leute frei sind, Beiträge zu leisten. Mit CI können Sie verhindern, dass Benutzer Code hinzufügen oder ändern, wenn der Code Ihr Programm beschädigt. Daher ist eine funktionierende Codebasis von unschätzbarem Wert.

    Wenn Sie Tests in Betracht ziehen, können Sie sicherlich einige End-to-End-Tests bereitstellen (ich denke, es ist eine Unterkategorie von Integrationstests), um sicherzustellen, dass Ihr Codefluss so funktioniert, wie er sollte. Sie sollten mindestens einige grundlegende Komponententests bereitstellen, um sicherzustellen, dass die Funktionen die richtigen Werte ausgeben, da im Rahmen der Integrationstests andere während des Tests gemachte Fehler kompensiert werden können.

  2. Die Erstellung von Testobjekten ist in der Tat ziemlich schwierig und mühsam. Sie haben Recht, wenn Sie Dummy-Objekte erstellen möchten. Diese Objekte sollten einige Standardwerte für die Groß- und Kleinschreibung haben, für die Sie sicherlich wissen, wie die Ausgabe aussehen soll.

  3. Das Problem bei Büchern zu diesem Thema ist, dass sich die Landschaft von CI (und anderen Teilen von Entwicklern) so schnell entwickelt, dass alles in einem Buch wahrscheinlich einige Monate später veraltet sein wird. Ich kenne keine Bücher, die Ihnen helfen könnten, aber Google sollte wie immer Ihr Retter sein.

  4. Sie sollten Ihre Tests mehrmals selbst ausführen und statistische Analysen durchführen. Auf diese Weise können Sie einige Testfälle implementieren, in denen Sie den Median/Durchschnitt mehrerer Läufe verwenden und mit Ihrer Analyse vergleichen, um festzustellen, welche Werte korrekt sind.

Einige Hinweise:

  • Verwenden Sie die Integration von CI-Tools in Ihre GIT-Plattform, um zu verhindern, dass fehlerhafter Code in Ihre Codebasis gelangt.
  • beenden Sie das Zusammenführen von Code, bevor andere Entwickler eine Peer-Review durchgeführt haben. Dies macht Fehler leichter bekannt und verhindert erneut, dass fehlerhafter Code in Ihre Codebasis gelangt.
1
Pelican

Mein Rat wäre, sorgfältig zu wählen, wie Sie Ihre Anstrengungen aufwenden. In meinem Bereich (Bioinformatik) ändern sich die Algorithmen auf dem neuesten Stand der Technik so schnell, dass der Energieverbrauch für die Fehlerprüfung Ihres Codes möglicherweise besser für den Algorithmus selbst aufgewendet werden kann.

Das heißt, was geschätzt wird, ist:

  • ist es die derzeit beste Methode in Bezug auf den Algorithmus?
  • wie einfach ist es, auf verschiedene Computerplattformen zu portieren (verschiedene HPC-Umgebungen, Betriebssystemvarianten usw.)?
  • robustheit - läuft es auf MEINEM Datensatz?

Ihr Instinkt, eine kugelsichere Codebasis aufzubauen, ist nobel, aber es lohnt sich daran zu denken, dass dies kein kommerzielles Produkt ist. Machen Sie es so portabel wie möglich, fehlerfrei (für Ihren Benutzertyp), bequem für andere, und konzentrieren Sie sich dann auf den Algorithmus selbst

0
pufferfish