Programmazione basata su contratto rispetto a Test unità

13

Sono un programmatore un po 'difensivo e un grande fan dei Contratti di codice di Microsofts.

Ora non posso sempre usare C # e nella maggior parte delle lingue l'unico strumento che ho sono asserzioni. Quindi di solito finisco con un codice come questo:

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

Tuttavia, questo paradigma (o come lo chiameresti tu) porta a un sacco di ingombri di codice.

Ho iniziato a chiedermi se valga davvero la pena di uno sforzo e se il test di unità adeguato lo avrebbe già coperto?

    
posta ronag 09.12.2013 - 10:17
fonte

6 risposte

14

Non penso che dovresti pensarlo come "vs".
Come menzionato nei commenti di @Giorgio, i contratti di codice servono a verificare gli invarianti (nell'ambiente di produzione) ei test di unità servono a garantire che il codice funzioni come previsto quando tali condizioni sono soddisfatte.

    
risposta data 09.12.2013 - 15:38
fonte
6

I contratti ti aiutano con almeno una cosa che i test unitari non hanno. Quando si sviluppa un'API pubblica non è possibile testare l'unità su come le persone utilizzano il proprio codice. Puoi comunque definire i contratti per i tuoi metodi.

Personalmente sarei rigoroso riguardo ai contratti solo quando si tratta di API pubbliche di un modulo. In molti altri casi probabilmente non ne vale la pena (e puoi usare invece i test unitari), ma questa è solo la mia opinione.

Questo non significa che raccomando di non pensare ai contratti in questi casi. Io penso sempre a loro. Non penso sia necessario codificarli sempre in modo esplicito.

    
risposta data 09.12.2013 - 15:47
fonte
1

Come già accennato, i contratti e i test unitari hanno uno scopo diverso.

I contratti riguardano la programmazione difensiva per assicurarsi che siano soddisfatti i prerequisiti, che venga chiamato il codice con i parametri corretti, ecc.

Test unitari per garantire che il codice funzioni, in scenari diversi. Questi sono come "specifiche con i denti".

Gli avvisi sono buoni rendono il codice robusto. Tuttavia, se sei preoccupato di aggiungere molto codice, potresti anche aggiungere punti di interruzione condizionali in alcuni punti durante il debug e ridurre il conteggio delle asserzioni.

    
risposta data 09.12.2013 - 16:51
fonte
0

Qualunque cosa tu abbia nelle tue richieste di checkVariants () potrebbe essere fatta da test, quanta fatica potrebbe effettivamente dipendere da molte cose (dipendenze esterne, livelli di accoppiamento ecc.) ma pulirà il codice da un punto di vista. Non sono sicuro che un codice-base sviluppato contro le asserzioni sia privo di refactoring.

Sono d'accordo con @duros, questi non dovrebbero essere pensati come approcci esclusivi o in competizione. Infatti in un ambiente TDD si potrebbe anche sostenere che le asserzioni 'requisiti' sarebbero necessarie per avere dei test:).

Tuttavia, NON RENDETE il codice più efficace a meno che non si faccia effettivamente qualcosa per correggere il controllo fallito, semplicemente si fermino i dati corrotti o simili, di solito interrompendo l'elaborazione al primo segno di difficoltà.

Una soluzione testata / ben testata avrà in genere già pensato e / o scoperto molte delle fonti / ragioni di input e output errati durante lo sviluppo dei componenti interagenti e li ha già trattati più vicino alla fonte del problema.

Se la tua fonte è esterna e non hai alcun controllo su di essa, per evitare di ingombrare il tuo codice con altri problemi di codice potresti prendere in considerazione l'implementazione di una sorta di componente di pulizia / asserzione dei dati tra l'origine e il tuo componente e mettere il tuo controlla lì.

Inoltre sono curioso di sapere quali lingue usi che non hanno una sorta di xUnit o altra libreria di test che qualcuno ha sviluppato, pensavo che ci fosse praticamente qualcosa per tutto in questi giorni?

    
risposta data 10.12.2013 - 21:36
fonte
0

Oltre ai test unitari e ai contratti di codice, ho pensato di mettere in evidenza un altro aspetto, che è il valore nella definizione delle interfacce in modo da eliminare o ridurre la possibilità di chiamare il codice in modo errato in primo luogo.

Non è sempre facile o possibile, ma sicuramente vale la pena di porsi la domanda: "Posso rendere questo codice più infallibile?"

Anders Hejlsberg, creatore di C #, ha affermato che uno dei più grandi errori in C # non includeva tipi di riferimento non annullabili. È uno dei motivi principali per cui esiste tanto materiale per la protezione del codice di guardia.

Tuttavia, il refactoring per avere solo la quantità necessaria e sufficiente di codice di protezione fa, secondo la mia esperienza, un codice più utilizzabile e mantenibile.

Accetta con @duros sul resto.

    
risposta data 11.12.2013 - 07:14
fonte
0

Fai entrambe le cose, ma crea alcuni metodi di supporto statici per chiarire le tue intenzioni. Questo è ciò che Google ha fatto per Java, controlla code.google.com/p/guava-libraries/wiki/PreconditionsExplained

    
risposta data 11.12.2013 - 08:00
fonte

Leggi altre domande sui tag