2013-02-20 7 views
9

Per quanto riguarda il test delle unità, mi è stato insegnato che il codice di produzione non dovrebbe contenere il codice relativo ai test.Le interfacce di un singolo implementatore per l'unità testano un antipattern?

Bene, mi sento come se infranassi questa regola ogni volta che provo al test unitario.

Ho una classe interna al mio assembly, Xyzzy. Voglio dipendere da una dipendenza in un'altra classe e poi stubla così posso testare l'altra classe in isolamento, quindi creo un'interfaccia, IXyzzy. Oops, ora ho il codice in produzione che è davvero lì solo per il test. Ancora peggio, sono andato contro l'interfaccia (descrive cosa può fare un implementatore do, non quello che è è). L'interfaccia pubblica di Xyzzy e IXyzzy sono esattamente uguali e nessun altro (tranne gli stub) implementa IXyzzy.

Sembra una cosa negativa per me.

ho potuto creare una classe base astratta o fare tutti i metodi pubblici che voglio testare il Xyzzy Overridable/virtual, ma che si sente male anche dal Xyzzy non è progettato per l'eredità e da una prospettiva YAGNI, non lo farà mai essere ereditato da

La creazione di interfacce per singolo implementatore è esclusivamente ai fini del test di un anti-pattern? Ci sono alternative migliori?

risposta

7

Non è sbagliato avere il codice solo per i test. Questo è in realtà normale, proprio come il codice di produzione contiene caratteristiche che vengono fatte solo per il debug e il monitoraggio della produzione. Non c'è una ragione chiara per cui questo dovrebbe essere vietato. Il codice dovrebbe supportare tutti gli aspetti del ciclo di vita dell'applicazione. I test sono solo un'altra parte del ciclo di vita.

In questo senso l'approccio con le interfacce è corretto. Se il resto dell'applicazione di produzione utilizza anche l'interfaccia (e non la classe concreta sebbene ne sia solo una), è architettonicamente valida.

Ho tipo di andata contro ciò interfaccia è (descrive ciò che un realizzatore può fare, non è quello che è)

non ho avuto il tuo punto qui perché l'interfaccia non descrivere qual è il l'oggetto può fare. Essendo una sola implementazione concreta (produzione) non distrugge questa proprietà.

Se ci pensate, ogni classe ha una "interfaccia" in un senso più ampio della parola: la firma pubblica di tutti i metodi espone un'interfaccia che la classe supporta all'esterno. Se un'interfaccia .NET è implementata o meno è solo un dettaglio. La classe fa ancora le stesse promesse all'esterno.

+1

Molto vero, molte delle mie interfacce, ad es. 'IRequestor', descrivi cosa fa;) –

3

Nella mia esperienza, questo è piuttosto tipico dello sviluppo .NET, derivante dal fatto che il metodo di sovrascrittura è basato su opt-in; se vuoi prendere in giro una dipendenza, hai bisogno di un'interfaccia o di un oggetto i cui metodi sono tutti virtuali.

In un linguaggio come Java, in cui ogni metodo è un'interruzione delle singole interfacce di implementazione singola è davvero un antipattern e i buoni sviluppatori lo chiameranno.

Continua a fare quello che stai facendo - qualsiasi peccato tu stia commettendo è, a mio avviso, facilmente superato dai benefici del tuo test di unità!

+2

Concordato sui vantaggi dei test unitari;) Interessante articolo sul perché C# non ha metodi di istanza che sono virtuali di default: http://geekswithblogs.net/madhawa/archive /2006/09/17/91418.aspx –

+0

Link interessante, grazie! – Ben

2

Sì, è un anti-pattern.Un modello sarebbe "una soluzione a un problema comune in un determinato contesto". Ma in questo caso, quello che abbiamo è un , non una soluzione.

Il problema in questione è la necessità di isolare un'unità da testare (alcune delle) sue dipendenze, in modo che l'implementazione di tali dipendenze non debba essere presa in considerazione durante la scrittura dei test di unità. La soluzione generale e vera a questo problema è chiamata "mocking", in cui il test writer può specificare qualsiasi comportamento sia necessario dalle dipendenze fittate.

Al contrario, forzare lo sviluppatore a creare interfacce separate non necessarie, o dichiarare metodi come virtual, è solo una soluzione per l'incapacità tecnica di isolare in modo pulito un'unità da altre.

Per .NET, esistono diversi strumenti di simulazione che forniscono questa capacità di isolamento, ovvero TypeMock Isolator, JustMock e MS Fakes. Altri linguaggi/piattaforme (inclusi Java, Ruby e Python) hanno i loro stessi strumenti di potere espressivo simile.

+1

C'è una buona domanda di SO che parla dell'ultima parte della risposta: [Stanno usando le interfacce Soley per facilitare lo stubing e il derisione nei test delle unità ora obsoleto?] (Http://stackoverflow.com/q/3869002/945456) –