2011-11-22 31 views
7

Voglio testare un pezzo di codice che restituisce un oggetto.Test unitario ... come migliorarlo

Io uso NUnit e in una classe di test, scrivo un metodo per verificare se il mio metodo funziona bene ...

[Test] 
public void GetMyObjectFromLog() 
{ 
    string _xmlFilePath = @"C:\XmlFile.xml"; 
    MyObjectParser _myObjectParser = new MyObjectParser(); 
    MyObject _mockMyObject = new MyObject 
           { 
            Title = "obj", 
            Name = "objName" 
           } 
    MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath); 

    Assert.AreEqual(_mockMyObject , _myObject); 
} 

Questo test non funziona perché MyObject non sovrascrive Equals metodo, e io don Non voglio sovrascrivere il metodo Equals solo per scopi di test.

Così ho riscrivere il test come questo:

[Test] 
public void GetMyObjectFromLog() 
{ 
    string _xmlFilePath = @"C:\XmlFile.xml"; 
    MyObjectParser _myObjectParser = new MyObjectParser(); 
    MyObject _myObject = _myObjectParser.GetMyObjectFromLog(_xmlFilePath); 

    Assert.AreEqual("obj", _myObject.Title); 
    Assert.AreEqual("objName", _myObject.Name); 
} 

Ok, funziona ... ma questo test è pertinente? Inoltre, c'è una dipendenza da un file.

È pertinente utilizzare un quadro Mock anziché? E come usarlo?

Grazie!

+0

In realtà si comarison potrebbe essere scritto in una sola riga, ma ha cattiva leggibilità: 'Assert.That (myObjectA, Is.EqualTo (myObjectB) .using ((x, y) => x.Name == y .Nome && x.Titolo == y.Title? 0: 1)); ' – Restuta

risposta

1

è assolutamente ok avere un riferimento a un file. Generalmente ci sono due tipi di test: unit test e test di integrazione.

I test di integrazione interagiscono sempre con alcuni file/database o con qualsiasi cosa. Nel tuo caso potresti migliorare il test prendendo in giro _myObjectParser.GetMyObjectFromLog.

Potresti scrivere tu stesso il modello o utilizzare un quadro come i rhinomock. Un ottimo libro per nunit/rhinomocks è: The Art of Unit Testing.

una versione migliore verificabile di GetMyObjectFromLog potrebbe essere la seguente:

public MyObject GetMyObjectFromLog(IMyXmlReader reader) 
{ 
    var xmlData = reader.GetData(); 
    //make your object here 
    var obj = new MyObject(xmlData); 
    return obj; 
} 

È quindi possibile implementare 2 nuove classi che implemments un'interfaccia IMyXmlReader, uno che legge da un file per il codice produttivo, e uno che ritorna solo sempre la stessa stringa su GetData().

È quindi possibile utilizzare la classe che restituisce sempre una stringa statica per i test dell'unità.

Comprendere? Scusa per il mio inglese :)

+1

Gesù ... perché dovrei aggiungere soluzioni allo stack overflow se qualcuno lo butta sempre giù. Non mi piace quello – Grrbrr404

+0

Lol. Anche lui mi ha votato. Cerchi di aiutare e questo è quello che ottieni :) –

+0

E la domanda ottiene 3 voti lol. –

1

Sì, sembra così. Tuttavia, è possibile eseguire l'override di Equals nel progetto di test, se non è necessario nel progetto principale. Per esempio. Di solito creo classi che promuovono classi private e protette a quelle pubbliche. Quindi sei libero di estendere il tuo progetto principale per testare semplicemente il tuo progetto di test.

Una dipendenza file è ok, basta inserire questo file nel progetto della suite di test.

0

Lo scopo di test di unità è quello di testare la logica del codice, il test di cui sopra sta facendo due cose: 1. Logic 2. Ricerca

ho detto ricerca, perché si sta tentando di corrispondere a un oggetto che hai creato in un file esterno. Se lo fai, il problema è che la tua build inizierà a rompersi se non ci sono file esterni presenti e non lo vuoi.

Soluzione: Creare il file in movimento ma non creare un file fisico, creare un file in memoria e quindi inserire l'oggetto che è necessario abbinare, quindi abbinare l'oggetto.

In questo modo questo test non si interromperà mai.

+0

Perché hai votato questo? –

+1

Non l'ho votato in difetto, ma la tua risposta non ha senso - non puoi creare un file in memoria. Il file è una classe statica. Intendevi Stream? –

2

proposito che la dipendenza sul file (che appare anche non essere nel progetto!):

Si poteva ignorare che _myObjectParser.GetMyObjectFromLog ad accettare anche un ruscello. Quindi è possibile aggiungere il file XML come risorsa incorporata e leggerlo dall'assieme.

5

Prima di tutto, il metodo all'interno del parser dovrebbe essere "Parse" anziché "Get".

In secondo luogo, se non si desidera che l'oggetto stesso sia in grado di confrontarsi con un altro, allora è perfettamente soddisfacente confrontarli come si faceva (proprietà per proprietà). Ma questo può essere estratto in un metodo di supporto nella classe di test.

Infine, non si desidera realmente accoppiare il parser con un file. Vuoi solo analizzare il testo. Se si desidera includere un metodo di supporto statico che apre anche un file e tutto, questa è la vostra scelta, ma non dovrebbe essere una dipendenza da istanza pura.

[Test] 
public void ParsesObjectFromXml() 
{ 
    string xmlInput = " ... "; 
    MyObjectXmlParser parser = new MyObjectXmlParser(); 
    MyObject expected = new MyObject() {Title = "obj", Name="objName"}; 

    AssertMyObjectsAreEqual(expected, parser.Parse(xmlInput)); 
} 

private bool AssertMyObjectsAreEqual(MyObject expected, MyObject actual) 
{ 
    Assert.AreEqual(expected.Title, actual.Title); 
    Assert.AreEqual(expected.Name, actual.Name); 
} 

Ora la tua classe e il tuo test sono più chiari e hanno una sola responsabilità.