2013-01-17 6 views
36

Come si gestisce la visibilità delle funzioni e il test delle unità in Haskell?Privacy delle funzioni e test delle unità Haskell

Se si esportano tutte le funzioni in un modulo in modo che i test delle unità possano accedervi, si rischiano altre persone che chiamano funzioni che non dovrebbero essere nell'API pubblica.

Ho pensato di utilizzare {-# LANGUAGE CPP #-} e poi che circonda le esportazioni con un #ifdef:

{-# LANGUAGE CPP #-} 

module SomeModule 
#ifndef TESTING 
(export1 
, export2 
) 
#endif 
where 

C'è un modo migliore?

+0

Possibile duplicato di https://stackoverflow.com/questions/34571/how-do-i-test-a-class-that-has-private-methods-fields-or-nernerclasses – Raedwald

risposta

55

La convenzione usuale è quello di dividere il modulo in parti pubbliche e private, cioè

module SomeModule.Internal where 

-- ... exports all private methods 

e poi l'API pubblica

module SomeModule where (export1, export2) 

import SomeModule.Internal 

Quindi è possibile importare SomeModule.Internal nei test e in altri luoghi dove la sua fondamentale per ottenere l'accesso all'implementazione interna.

L'idea è che gli utenti della vostra biblioteca mai accidentalmente chiamata API private, ma essi possono usarlo se la sanno quello che stanno facendo (debugging, ecc). Ciò aumenta notevolmente l'usabilità della tua libreria rispetto a nascondere forzatamente l'API privata.

+1

Interverrà questo inlining (ottimizzazioni in fase di compilazione)? Leggendo https://www.haskell.org/haskellwiki/Performance/GHC#Inlining sembra che sarebbe ... Quindi puoi scrivere test unitari o ottimizzare? (per favore, qualcuno mi dica che ho torto!) – tlo

+0

Se la preoccupazione è che l'ottimizzazione in linea, una volta disabilitata da questa tecnica, si noti che è ancora possibile utilizzare l'inlining esplicito per garantire che ciò avvenga. – Jules

+0

Per chiunque cerchi di usare questo consiglio con Haskell-Stack, per creare il modulo 'SomeModule.Internal', è necessario creare una struttura di directory adatta - vedere [questa domanda] (https://stackoverflow.com/questions/28193295/ carico-a-module-in-ghci-by-nome-modulo-modulo-nome quando-doesnt match-file-name). – hnefatl

7

Per il test, in genere si divide l'applicazione nel file di progetto cabal, tra una libreria, l'eseguibile di produzione e un eseguibile test-suite che verifica le funzioni della libreria, quindi le funzioni di asserzione vengono mantenute separate.

Per la visibilità delle funzioni esterne, i moduli della libreria sono divisi tra la sezione "moduli esposti" e la sezione "altri moduli".

+0

per riferimento ecco un esempio di pacchetto cabal per un eseguibile, che è diviso in libreria ed eseguibile: http://www.haskell.org/cabal/users-guide/developing-packages.html#configurations –

+0

Can the testsuite contiene test contro moduli nella sezione 'altri-moduli'? I test interni delle unità senza esporli a clienti esterni mi sembrano molto desiderabili. – Blaisorblade

+1

@Blaisorblade yes, il modo per accedere alla suite di test da 'other-modules' è specificare nel file cabal' hs-source-dirs: src, tests' per la suite di test. In altre parole, 'src' è anche compilato nella suite di test. Il rovescio della medaglia è che si compila la sorgente due volte: nel modo normale, e poi ancora per i test. Ma questo è il modo migliore che conosco. –