2012-04-02 11 views
7

Ho un numero di moduli "libreria" in OCaml (principalmente funzioni di utilità e di supporto) dove ho aggiunto il seguente tipo di codice alla fine per test unitari banali:più "rete" nei moduli OCaml collegati

let main() = ... 
main 

o

let() = ... 

Questo codice essere che principalmente stampe alla console (per scopi di test semplici). Il problema ora è che quando collego i miei moduli "library" con il mio modulo "principale" ed eseguo il programma ottengo tutti questi messaggi di test che distraggono. C'è un modo per includere il codice in un modulo OCaml che viene eseguito quando il modulo è collegato da solo (facilitando così i test banali) ma non quando viene usato come una "libreria"? Ho letto post in SO per l'effetto che OCaml non ha la nozione di un modulo "principale" e che tutti i moduli sono uguali tuttavia mi sembra che l'ordine dei file oggetto dati al linker possa essere interpretato per indicare che il l'ultimo modulo è quello "principale" (poiché è in cima alla "catena alimentare di dipendenza").

risposta

7

OCaml supporta il collegamento statico e il caricamento dinamico dei moduli; quello che fai normalmente (e che cos'è il tipo sicuro) è il collegamento statico. Raccomanderei solo il caricamento dinamico se hai bisogno di qualche tipo di architettura di plugin.

In ogni caso, una libreria non è altro che un modulo (probabilmente con sotto-moduli). Se si collega staticamente un modulo, tutte le routine "principali" verranno eseguite nell'ordine dei moduli collegati nel file eseguibile.

Quindi, se non si fa nulla, un modulo non sa in quale eseguibile viene collegato in modo "magico"; ciò che si dovrebbe fare è imho:

  • spostare i test fuori dei moduli, magari utilizzando ounit O
  • almeno riscrivere i tuoi test-funzioni per essere funzioni reali, per esempio "let test() = ..."; quindi scrivi un frontend di test che chiamerà tutte le funzioni di "test" da tutti i tuoi moduli.

addendum:

Se lo fai in altre lingue, non sembra esserci nessuna torta libera sia:

In Java se si dispone di più di rete nel codice, è necessario in modo esplicito selezionare quello che si desidera eseguire l'eseguibile.

In C è possibile utilizzare il preprocessore C per fare qualcosa di simile

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

OCaml ha il suo preprocessore camlp4 (camlp4 wikipedia article) con la quale si potrebbe fare qualcosa di simile. Personalmente considero questo tipo di integrazione di test come una cattiva ingegneria del software. Dovresti piuttosto testare il tuo modulo/classe/.. dal lato dell'interfaccia e contrassegnare i tuoi invarianti interni con asserzioni (che esistono in Java, C & OCaml).

+0

In C hai ragione, avresti bisogno di usare un frontend di testing ma in Java è una pratica comune per ogni classe non banale avere un main() facendo una sorta di "testing" di tipo "corsivo" - quando ti sposti una struttura di test che tipo di codice viene ripulito e non serve a nessuno scopo ma durante lo sviluppo attivo iniziale questa struttura ha il suo uso. Mi rendo conto che in OCaml hai il livello più alto ma non è la stessa cosa. –

+0

commento: vedi addendum – lambdapower

5

La toolchain non dispone di alcuna disposizione per questo, genera un file che esegue il codice di livello superiore di tutti i moduli all'avvio, in ordine di collegamento.

Non vedo come farlo funzionare sistematicamente. I moduli hanno quasi sempre un codice di livello superiore che deve essere eseguito. Avresti bisogno di un modo per separare il codice di primo livello in due gruppi (un gruppo viene sempre eseguito, l'altro solo eseguito quando il modulo è l'ultimo a essere collegato). Questo sembra inutilmente disordinato.

Una soluzione migliore (a mio avviso) è solo quella di utilizzare un framework di test leggermente più sofisticato.