2012-04-02 3 views
7

Ich habe eine Reihe von "Bibliothek" -Modulen in OCaml (hauptsächlich Dienstprogramm-und Hilfsfunktionen), wo ich die folgende Art von Code am Ende für triviale Unit-Tests hinzugefügt haben:mehrere "Hauptleitungen" in verknüpften OCaml-Modulen

let main() = ... 
main 

oder

let() = ... 

Dieses Wesen Code, der in erster Linie druckt auf die Konsole (für einfache Testzwecke). Das Problem ist jetzt, dass wenn ich meine "Bibliothek" -Module mit meinem "Haupt" -Modul verknüpfe und das Programm ausführe, bekomme ich all diese ablenkenden Testnachrichten. Gibt es eine Möglichkeit, Code in ein OCaml-Modul einzubinden, das ausgeführt wird, wenn das Modul alleine verbunden ist (wodurch triviale Tests möglich sind), aber nicht, wenn es als "Bibliothek" verwendet wird? Ich habe Beiträge in SO gelesen, in denen OCaml keine Ahnung von einem "Haupt" -Modul hat und dass alle Module gleich sind, aber es scheint mir, dass die Reihenfolge der Objektdateien, die dem Linker gegeben werden, so interpretiert werden könnte Letztes Modul ist das "Haupt" (da es an der Spitze der "Abhängigkeits-Nahrungskette" steht).

Antwort

7

OCaml unterstützt statische Verknüpfung und dynamisches Laden von Modulen; Was Sie normalerweise tun (und was ist sicher) ist statische Verknüpfung. Ich würde das dynamische Laden nur empfehlen, wenn Sie eine Art Plugin-Architektur benötigen.

Wie auch immer, eine Bibliothek ist nichts anderes als ein Modul (wahrscheinlich mit Untermodulen). Wenn Sie ein Modul statisch verknüpfen, werden alle "Haupt" -Routinen in der Reihenfolge der Module ausgeführt, die in Ihrer ausführbaren Datei verknüpft sind.

Also, wenn Sie nichts dagegen tun, weiß ein Modul nicht, in welche ausführbare Datei es auf irgendeine "magische" Weise verbunden wird; was sollte man imho tun ist:

  • bewegen die Tests aus den Modulen, vielleicht mit ounit OR
  • mindestens umschreiben Ihre Testfunktionen reale Funktionen, z.B. "lass test() = ..."; Schreiben Sie dann ein Test-Frontend, das alle "Test" -Funktionen von all Ihren Modulen aufruft.

Nachtrag:

Wenn Sie in anderen Sprachen zu tun, dass es keinen freien Kuchen zu sein scheint entweder:

In Java Sie, wenn Sie mehrere Netze in Ihrem Code haben, müssen Sie explizit Wählen Sie die Datei aus, von der die ausführbare Datei ausgeführt werden soll.

In C können Sie den C-Präprozessor verwenden so etwas wie

#ifdef TEST_1 
int main() { 
... 
} 
#endif 

OCaml hat seinen eigenen Präprozessor camlp4 (camlp4 wikipedia article) zu tun, mit dem Sie etwas Ähnliches tun könnte. Ich persönlich halte diese Art der Testeinbettung für eine schlechte Softwareentwicklung. Sie sollten stattdessen Ihr Modul/class/.. von der Interfaceseite aus testen und Ihre internen Invarianten mit Assertions (die in Java existieren, C & OCaml) markieren.

+0

In C sind Sie richtig, Sie müssten ein Test-Frontend verwenden, aber in Java ist es eine übliche Praxis für jede nicht-triviale Klasse, eine main() eine Art oberflächliches "Testen" zu haben - wenn Sie umziehen Ein Testframework, dass diese Art von Code aufgeräumt wird und keinem weiteren Zweck dient, aber während der anfänglichen aktiven Entwicklung hat diese Einrichtung ihren Nutzen. Ich weiß, dass du in OCaml den Toplevel hast, aber es ist nicht dasselbe. –

+0

Kommentar: siehe Anhang – lambdapower

5

Die Toolchain hat keine Vorkehrungen dafür. Sie generiert eine Datei, die den obersten Code aller Module beim Start in der Reihenfolge der Verknüpfung ausführt.

Ich sehe nicht, wie man es systematisch arbeiten lässt. Module enthalten fast immer Code auf oberster Ebene, der ausgeführt werden muss. Sie müssten den Code der obersten Ebene in zwei Gruppen aufteilen (eine Gruppe wird immer ausgeführt, die andere nur ausgeführt, wenn das Modul als letztes verknüpft ist). Dies scheint unnötig unordentlich zu sein.

Eine bessere Lösung (es scheint mir) ist nur ein etwas ausgeklügeltes Testframework zu verwenden.

Verwandte Themen