Strategien für Unit-Tests und testgetriebene Entwicklung

16

Ich bin ein großer Verfechter der testgetriebenen Entwicklung im wissenschaftlichen Rechnen. Die Nützlichkeit in der Praxis ist einfach umwerfend und lindert die klassischen Probleme, die Codeentwickler kennen. Das Testen von wissenschaftlichen Codes, die bei der allgemeinen Programmierung nicht vorkommen, ist jedoch mit gewissen Schwierigkeiten verbunden. Daher sind TDD-Texte als Tutorials nicht besonders nützlich. Beispielsweise:

  • Im Allgemeinen kennen Sie keine genaue Antwort auf ein bestimmtes komplexes Problem von vornherein. Wie können Sie also einen Test schreiben?

  • Der Grad der Parallelität ändert sich; Ich bin kürzlich auf einen Fehler gestoßen, bei dem die Verwendung von MPI-Aufgaben als Vielfaches von 3 fehlschlug, aber ein Vielfaches von 2 funktionierte. Darüber hinaus scheinen gängige Test-Frameworks aufgrund der Natur von MPI nicht sehr MPI-freundlich zu sein. Sie müssen eine Test-Binärdatei erneut ausführen, um die Anzahl der Tasks zu ändern.

  • Wissenschaftliche Codes haben oft viele eng gekoppelte, voneinander abhängige und austauschbare Teile. Wir haben alle den alten Code gesehen und wissen, wie verlockend es ist, auf gutes Design zu verzichten und globale Variablen zu verwenden.

  • Häufig ist eine numerische Methode ein "Experiment", oder der Codierer versteht nicht vollständig, wie sie funktioniert, und versucht, sie zu verstehen. Daher ist es unmöglich, Ergebnisse vorwegzunehmen.

Einige Beispiele für Tests, die ich für wissenschaftlichen Code schreibe:

  • Verwenden Sie für Zeitintegratoren eine einfache ODE mit einer genauen Lösung, und prüfen Sie, ob Ihr Integrator diese mit einer bestimmten Genauigkeit löst. Die Reihenfolge der Genauigkeit ist korrekt, indem Sie mit verschiedenen Schrittgrößen testen.

  • Nullstabilitätstests: Stellen Sie sicher, dass eine Methode mit 0 Rand- / Anfangsbedingungen bei 0 bleibt.

  • Interpolationstests: Bei gegebener linearer Funktion stellen Sie sicher, dass eine Interpolation korrekt ist.

  • Legacy-Validierung: Isolieren Sie einen Teil des Codes in einer Legacy-Anwendung, von der bekannt ist, dass sie korrekt ist, und ziehen Sie einige diskrete Werte zum Testen heraus.

Es kommt immer noch oft vor, dass ich nicht herausfinden kann, wie man einen bestimmten Codeabschnitt richtig testet, abgesehen von manuellen Versuchen und Irrtümern. Können Sie einige Beispiele für Tests angeben, die Sie für numerischen Code schreiben, und / oder allgemeine Strategien zum Testen von wissenschaftlicher Software?

Aurelius
quelle
Könnten Sie bitte klarstellen, was Sie mit Interpolationstests meinen?
Dmitry Kabanov

Antworten:

8

Methode der hergestellten Lösungen .

Stellen Sie durch Verfeinerungsstudien sicher, dass die Methode die theoretische Genauigkeitsordnung erreicht.

Bewahrung der Antwort. Bit- und normgerechte Wiedergabe von Lösungen.

Bill Barth
quelle
Ich wollte MMS im ursprünglichen Beitrag erwähnen. Es ist gut für die Codeüberprüfung, aber aus der Sicht der Einheitentests völlig wertlos. Wenn diese Tests fehlschlagen, gibt es keinen Hinweis darauf, wo oder warum.
Aurelius
3
2×2×2
Ein Großteil der Literatur, die ich über MMS gesehen habe, ist im Grunde genommen eine globale Lösung, z. B. für CFD-Probleme. Eine hergestellte Lösung könnte eine Tragflächenanalyse sein. Wenn dieser Test fehlschlägt, haben Sie den Täter bestenfalls auf 5.000 Codezeilen eingegrenzt. Für TDD ist das also ziemlich wertlos - Sie haben keine Ahnung, wo der eigentliche Fehler auftritt. Ich stimme zu, dass ein 2x2x2-Problem äußerst wertvoll ist und ich persönlich viel davon benutze. Es kommt jedoch häufig vor, dass ich auf Probleme stoße, die nur bei größeren Systemen auftreten. Tatsächlich habe ich kürzlich einen ifort-Compiler-Fehler gefunden, der sich nur in großen Problemen manifestierte.
Aurelius
@ Aurelius: Kein Argument hier. Sie sollten über eine Reihe von Tests verfügen und diese regelmäßig ausführen.
Bill Barth
@Aurelius Bei MMS handelt es sich nicht um einen Komponententest, sondern um einen Funktions- oder Abnahmetest (dh des gesamten Systems). Codes haben jedoch oft separate Stufen (oder können in diese unterteilt werden). zB Advektion, Druck, Viskosität. Man könnte dann nur eine dieser Stufen testen (eine "Einheit"). Ebenso könnte ein Code ohne BC und dann mit einem getestet werden. Ein Freund hat über Unit-Tests promoviert und er meinte, der größte Vorteil sei, dass Sie dazu gezwungen wurden, Ihr Programm in Units zu unterteilen, damit es Unit-getestet werden kann auf andere Weise weiß ich nicht).
Hyperpallium
6

Bill hat bereits einige Methoden aufgelistet, die auf Ihre Bedenken eingehen.

Wenn Sie Ihren dritten Punkt ansprechen, nein, es gibt keinen Grund, eine starke Kopplung zwischen Teilen einzuführen. Im Gegenteil: Wenn Ihre Funktionen oder Klassen gut definierte Schnittstellen haben, ist es viel einfacher, beispielsweise einen linearen Löser gegen einen anderen oder ein Zeitschrittschema auszutauschen. Einfach widerstehen, und dann können Sie diese Komponenten separat testen. Wir haben dies mit deal.II seit Jahrzehnten getan.

Zu Ihrem vierten Punkt: Wenn Ihre Methode ein Experiment ist, sind Ihre Experimente mit der Methode ein Test. Solange Sie keine Analyse haben, müssen Sie diese Testergebnisse als am besten verfügbar ansehen. Aber normalerweise haben Sie eine Erwartung zum Beispiel für die Reihenfolge einer Methode, oder Sie würden wissen, dass sie für eine bestimmte Klasse von Lösungen genau ist, zum Beispiel Polynome bis zu einem gewissen Grad. Die Überprüfung sollte Teil Ihrer Experimente sein. Wenn sich die Analyse verbessert, können Tests hinzugefügt werden.

Guido Kanschat
quelle
1
Um die Antwort von Guido zu ergänzen, wird die Erfahrung, von der er spricht, in den ~ 3.000 Tests verschlüsselt, die wir bei deal.II nach jeder Änderung durchführen: dealii.org/developer/development/… . Bei der Frage, was zu tun ist, wenn Sie die genaue Antwort nicht kennen: Schreiben Sie trotzdem einen Test und lassen Sie die heutige Antwort mit der gestrigen Antwort vergleichen (oder wann immer Sie den Test geschrieben haben). Die Möglichkeit, Änderungen in der Ausgabe eines Codes zu erkennen, ist auch dann von Nutzen, wenn Sie nicht wissen, ob die Antwort falsch war oder eine zuvor falsche Antwort korrigiert wurde.
Wolfgang Bangerth
3

Ich habe kürzlich diese Dissertation über TDD in Computational Science gefunden. Ich habe es noch nicht gelesen, daher habe ich keine Ahnung, ob es etwas Gutes ist, aber hoffentlich kann es hilfreich sein.

http://cyber.ua.edu/files/2014/12/u0015_0000001_0001551.pdf

Zeitschriften
quelle
1
Ich habe einige der Intro- und Schlussfolgerungen überflogen und dabei ein Qualitätsniveau angenommen, das mit der Standard-Doktorarbeit vergleichbar ist. Dies erklärt sowohl den Prozess (auf hohem Niveau) als auch die tatsächlichen Messungen hinsichtlich seiner Wirksamkeit. Ich denke, das ist eine ziemliche Entdeckung.
Godric Seer
Der Link ist tot. Meinten Sie: Nanthaamornphong, A. „Die Wirksamkeit von testgetriebenen Entwicklungs- und Refactoring-Techniken in der Softwareentwicklung für Computer- und Ingenieurwissenschaften“. Dissertation, Uni. Alabama (2014).
AlQuemist,