2009-06-10 23 views
19

Scenario. Language C#, Test delle unità utilizzando il framework di test dell'unità VS2008UnitTesting Static Classes

Ho una classe statica con un costruttore statico e 2 metodi. Ho 4 metodi di prova scritti per testare l'intera classe. My Static Constructor ha alcune importanti inizializzazioni.

Ora se eseguo tutti i 4 casi di test dell'unità in tandem, il costruttore statico sarà chiamato solo all'inizio. Alla fine di ogni caso di test, non c'è nulla di simile

chiamato distruttore statico, quindi le informazioni di stato nel costruttore vengono trasferite anche al caso di test dell'unità successiva . Qual è la soluzione per questo.

risposta

11

La soluzione più semplice è aggiungere un metodo "Reset" alla classe statica, che avrebbe il comportamento equivalente di distruggerlo e ricostruirlo.

Potrebbe esserci un motivo valido per cui si sta utilizzando una classe statica qui. Tuttavia, poiché la statica non funziona bene con i test unitari, di solito cerco un design alternativo.

0

Bene, non hai specificato quale lingua stavi usando, ma se c'è un modo per aprire la tua classe statica all'interno del file di test, allora aggiungerei un falso distruttore, che puoi chiamare dopo ogni test. In questo modo, il "distruttore" rimane nella classe di test e fuori dal tuo codice di produzione.

0

È possibile utilizzare Typemock's Isolator che è in grado di simulare classi statiche, quindi in ogni test è possibile "definire" come funzionerà la statica.

Tuttavia, non è un prodotto gratuito.

0

Sembra che tu stia provando a testare il costruttore statico. Questa sembra una cattiva idea.

Considerare invece di estrarre la logica di inizializzazione in una classe separata (non statica).

Per motivi di discussione, diciamo che la classe statica si chiama MySingleton e, diciamo che si crea una nuova classe denominata MyInitializer, con un metodo Execute. Il costruttore statico di MySingleton potrebbe istanziare MyInitializer e chiamare Execute, che esegue l'inizializzazione.

Quindi il codice di produzione potrebbe utilizzare MySingleton e ignorare MyInitializer. I tuoi test, d'altra parte, potrebbero ignorare MySingleton e creare allegramente una nuova istanza MyInitializer per ogni test, ottenendo un nuovo inizio ogni volta.

1

Conoscere l'uso della classe che commenta solo l'utilizzo è un po 'complicato, ma lo ammetto comunque. Per me quanto sopra sembra un odore più che un problema di test.

Una classe statica (proprio come i singleton) sono fondamentalmente una raccolta di funzioni/variabili globali che generalmente è una brutta cosa in oop. Direi che provare a testare il problema del test è (probabilmente probabilmente il più semplice in questo momento) solo correggendo il sintomo ma non il problema.

io suggerirei di dare un'occhiata al desing un concidere se si ha realmente bisogno la classe statica o se mi sembrava il modo più semplice per risolvere un problema al momento

5

vorrei spostare l'inizializzazione da il costruttore statico a un metodo che viene chiamato dal costruttore.Rendendo questo metodo interno, è possibile chiamare questo metodo dai test per reinizializzare la classe.

public static class MyClass 
{ 
    public static MyClass() 
    { 
     initialize(); 
    } 

    internal static void initialize() 
    { 
     // Do initialization (and cleanup if necessary) 
    } 

    public static void Method1() {} 
    public static void Method2() {} 
} 

Per chiamare i metodi interni è necessario utilizzare l'attributo InternalsVisibleTo, come descritto in this blog.

Puoi anche renderlo privato, ma poi devi usare il riflesso per chiamarlo.

Ma come ha detto Andrew Shepherd, dovresti anche controllare se una classe statica è il miglior design di questa classe.

34
Type staticType = typeof(StaticClassName); 
ConstructorInfo ci = staticType.TypeInitializer; 
object[] parameters = new object[0]; 
ci.Invoke(null, parameters); 

da http://colinmackay.scot/2007/06/16/unit-testing-a-static-class/

+21

ehi guarda, una risposta effettiva alla domanda invece di "non farlo". – deltree

+0

Funziona bene, tuttavia ho dovuto dichiarare manualmente un costruttore statico vuoto nella classe (anche se normalmente non è necessario). –

+1

Perché i parametri vengono utilizzati per il costruttore statico? Possiamo chiamarlo come 'ci.Invoke (null, null);'? – SerG

0

Per ragioni di completezza, se è necessario ripristinare un campo non pubblica/variabile di una classe statica, è anche possibile farlo attraverso la riflessione.

using System.Reflection; // or Mono.Reflection 

public static class MyClass{ 
    private static string myString; 
} 

var newValue = "Potatoes";    
var field = typeof(MyClass).GetField("myString", BindingFlags.Static | BindingFlags.NonPublic); 
field.SetValue(null, newValue); // the first null is because the class is static, the second is the new value