2011-11-08 17 views
7

Ho letto la maggior parte delle domande relative a SO (here, here e there). L'ultima domanda propone quattro alternative per creare codice che chiama i metodi statici unitabili alla prova. Voglio chiedere del mio caso particolare: abbiamo un progetto "business logic layer" o "rules" che contiene 45 classi statiche (nessuno stato, solo metodi statici). Inoltre, non sono facilmente testabili da soli: la maggior parte di essi accede al database e al file system. Non è poi così male: per accedere al database, usano l'istanza unica di alcune classi Mapper (tutti i Mapper sono Singletons). Ogni volta che provo a testare qualcosa, mi imbatto in questo muro. Il problema più grande è che questo è un codice molto, molto importante, e le modifiche dovrebbero essere pianificate con molta attenzione. La mia domanda: come devo fare per rendere questa unità più testabile? Devo scrivere 45 interfacce e usare l'iniezione di dipendenza? Anche così, come faccio a mozzare/schernire i mappatori?Codice di test unitario che chiama metodi statici

PS: Ho letto Michael Feathers' 'Lavorare con il codice legacy', in modo da riferimenti diretti sono i benvenuti (altri libri troppo :)

Edit: Dal momento che alcune persone hanno detto le soluzioni potrebbero essere dipendente dalla piattaforma , Sto lavorando su .NET (C# e alcuni VB.NET)

risposta

10

La situazione attuale è probabilmente che nessuno osa modificare qualcosa nel codice perché potrebbe rompersi in modi imprevisti. Assicurarsi che tutti comprendano che si sta migliorando la situazione: le modifiche potrebbe rompere il codice, ma a differenza di prima, quelle rotture saranno trovato e una volta sono stati trovati, saranno fissati sempre.

Detto questo, il passaggio successivo dipende dalla tua esperienza e dal tuo credito con il team. Se si vuole andare sul sicuro, utilizzare il codice come questo (sintassi Java):

Mapper { 
    public static Mapper INSTANCE = new Mapper(); // NEW code 

    protected void doImpl() { // NEW CODE 
     ... code copied from impl()... // OLD code, NEW PLACE 
    } 

    public static void impl() { // OLD code 
     INSTANCE.doImpl(); // NEW code 
    } 

    // OLD code ... 
} 

Si tratta di un cambiamento molto semplice che permette di sovrascrivere INSTANCE dalle vostre prove. Per il codice di produzione, non fai nulla e il default farà sì che il codice si comporti esattamente come prima.

In questo modo, è possibile sostituire un metodo alla volta. Puoi smettere di seguire questo percorso in qualsiasi momento - ogni cambio richiede solo un paio di minuti ed è un refactoring: il codice fa esattamente quello che faceva prima. Poiché ogni cambiamento è così piccolo e non può rompere nulla, è possibile sostituire un metodo, scrivere tutti i test unitari che non si potevano scrivere prima, risciacquare, ripetere. Infine, se non si desidera/deve rielaborare tutti i metodi statici, questo approccio offre tutto il margine che si potrebbe desiderare.

In una seconda fase, è possibile introdurre DI o qualsiasi altra tecnologia che possa renderti felice. Il vantaggio di questo approccio: quando arrivi alle modifiche complesse, avrai già dei test unitari che ti proteggeranno.

Se hai iniziato con DI, dovresti modificare molto codice in tutti i tipi di posizioni, senza test di unità adeguati che potrebbero proteggerti.

2

La tua domanda è davvero legata alla piattaforma, nel mondo Microsoft è possibile utilizzare Microsoft Moles per testare metodi statici. E finti metodi statici.

Nel mondo Java ci sono probabilmente altri strumenti o dovresti evitare di usare la statica.

Su altre piattaforme ci sono altri strumenti, ecc

In generale, qualsiasi metodo statico renderà il vostro codice meno verificabile. A mio avviso, è meglio evitare statici e singleton (stato globale) ad ogni costo. Il codice verificabile è la parte più importante del tuo codice se vuoi cambiare qualcosa più tardi. Il codice verificabile è normalmente anche più leggibile.

Moles and Pex

3

rendere l'interfaccia della classe Mapper e sostituire la funzionalità mapper con una nuova implementazione moc. Penso che dovrai implementare la fabbrica astratta che genererà le istanze di Mapper. Quindi crea una IMapperFactory e due implementazioni di questo DBMapperFactory e MocMapperFactory passano l'istanza di questo oggetto al tuo codice dove accedi ai Mapper e li generi con questa istanza.

Gl.

+1

Suoni ok. Questo si sarebbe preoccupato di rendere testabili i metodi statici, ma che dire del codice che li chiama? In un'altra nota, solo curioso ... È "GI" una sorta di firma, o è un acronimo? (Vengo dall'Argentina) –

+0

Gl == Buona fortuna :). Per il codice che usa il Mapper devi adattarlo per usare l'interfaccia di fabbrica invece di getInstance di singleton. – AlexTheo

1

La classe statica può essere derisa, anche se senza sapere quale lingua/ambiente si sta utilizzando, non c'è modo di dire come.

Ho avuto una base di codice che si è conclusa esattamente come quello che hai detto; abbiamo creato interfacce e implementazioni predefinite di alcune dozzine di classi statiche (non fatevi prendere dal panico - generazione di codice). I comandi predefiniti sono solo delegati ai singleton.

Le classi di chiamata sono state commutate su DI utilizzando le impostazioni predefinite, ma sono state quindi molto più facili da testare. Le classi statiche con dipendenze su altre classi statiche o singletons si sono mossi verso l'utilizzo dell'implicazione predefinita.

Si prende in giro un singleton come qualsiasi altra classe - se ha uno getInstance (o equivalente) è possibile farlo restituire quello che vuoi. Oppure puoi seguire lo stesso percorso e usare DI.

+0

Ok, sto usando .NET (domanda aggiornata). È possibile prendere in giro una classe statica facilmente lì? –

+0

@dario_ramos Non ne ho idea, ma la risposta del pari implica che tu possa farlo. –

1

Ottima domanda! Puoi prendere in giro la tua classe Mapper creandone una nuova che erediti dalla classe Mapper singleton e utilizzarla per intercettare tutte le chiamate al tuo database.

Problemi correlati