2012-05-25 15 views
16

Sto cercando di imparare come eseguire il test dell'unità con C# e Moq e ho creato una piccola situazione di test. Dato questo codice:Unità di prova di un metodo con Moq

public interface IUser 
{ 

    int CalculateAge(); 
    DateTime DateOfBirth { get; set; } 
    string Name { get; set; } 
} 

public class User : IUser 
{ 
    public DateTime DateOfBirth { get; set; } 
    string Name { get; set; } 

    public int CalculateAge() 
    { 
     return DateTime.Now.Year - DateOfBirth.Year; 
    } 
} 

Voglio testare il metodo CalculateAge(). Per fare questo, ho pensato di provare a dare un valore predefinito alla proprietà DateOfBirth facendo questo nel mio metodo di prova:

var userMock = new Mock<IUser>(); 
userMock.SetupProperty(u => u.DateOfBirth, new DateTime(1990, 3, 25)); //Is this supposed to give a default value for the property DateOfBirth ? 
Assert.AreEqual(22, userMock.Object.CalculateAge()); 

Ma quando si tratta di l'affermazione, il valore di CalculateAge() è uguale a 0, anche se DateOfBirth eguali new DateTime(1990, 3, 25).

So che questo può sembrare un esempio stupido, ma qualunque cosa ... Ho pensato che potrei usare il mocking per dare valori a metodi/proprietà non ancora sviluppati nei miei oggetti, quindi il test di un metodo non sarebbe dipende da un altro componente della mia classe, o anche impostando un contesto predefinito per il mio oggetto (da qui il nome dell'utente qui ...) Sto affrontando questo problema nel modo sbagliato?

Grazie.

+1

* Davvero * bel articolo che si allinea in parallelo con la tua domanda: http://kakimotonline.com/2011/01/02/unit-testing-net-application-with-moq-framework/ – atconway

risposta

23

Sì, ti stai avvicinando male, ma non preoccuparti, spiegherò perché. Primo suggerimento sarebbe

è possibile rimuovere completamente la classe User e tutto sarà lo stesso .

quando si sta facendo:

var userMock = new Mock<IUser>(); 

È solo la creazione di un falso oggetto fittizio \ di tale interfaccia, che non ha nulla a che fare con la classe iniziale User, in modo che non ha alcuna implementazione di Metodo CalculateAge, ad eccezione di quello falso che restituisce semplicemente 0. È per questo che stai ricevendo 0 nella tua affermazione.

Quindi, dicevi:

pensato che avrei potuto usare beffardo per dare valori di non-ancora-sviluppato metodo/proprietà nei miei oggetti, in modo che la sperimentazione di un metodo non dipendere da un altro componente della mia classe

si potrebbe, diciamo che si avrà qualche consumatore della vostra IUSER, consente di dire come la seguente:

class ConsumerOfIUser 
{ 
    public int Consume(IUser user) 
    { 
     return user.CalculateAge() + 10; 
    } 
} 

in quel caso beffardo di IUSER farà totale senso, dal momento che si vuole verificare come i tuoi ConsumerOfIUser si comporta quando IUser.CalculateAge() restituisce 10. Si potrebbe procedere come segue:

var userMock = new Mock<IUser>(); 
userMock.Setup(u => u.CalculateAge()).Returns(10); 

var consumer = new ConsumerOfIUser(); 
var result = consumer.Consume(userMock); 

Assert.AreEqual(result, 20); //should be true 
+0

Quindi non c'è assolutamente alcun motivo usare Mocking mentre si prova una lezione da solo? Da solo intendo che non c'è interazione con altre classi. Ad esempio, supponiamo di avere un metodo che scarica un sacco di cose e che richiede 10 minuti per essere eseguito. E che CalculateAge() utilizza un valore restituito da questo metodo ... Sarebbe utile prendere in giro questo risultato? (Supponiamo che DateOfBirth sia il metodo di download di 10 minuti, anziché solo una proprietà automatica) – Pacane

+4

@Pacane, giusto. Testare una classe senza dipendenze esterne (nella sua forma più pura) non dovrebbe richiedere un mock o uno stub. – lbergnehr

+2

Il metodo per scaricare le cose dovrebbe essere scritto in un'altra classe, che può essere deriso per il test. – Ben

2

Dipende da che cosa il vostro cercando testare. In questo caso, hai deriso l'oggetto User, quindi non c'è motivo di testare qualcosa all'interno di questa classe mentre lo stai sostituendo con un oggetto fittizio. Se vuoi testare l'oggetto User, non devi prenderlo in giro.

I mazzi vengono utilizzati per sostituire gli oggetti dipendenti che non si desidera testare. Ad esempio, se avessi un oggetto Nome invece di una stringa (ad esempio, contiene nome, cognome, titolo ecc.) ma non volevi testare l'oggetto Name, solo l'oggetto User, dovresti creare una simulazione dell'oggetto Name da utilizzare quando costruisci l'oggetto User.

Problemi correlati