2012-10-22 9 views
9
[Test] 
public void testMultiplication() 
{ 
    var five=new Dollar(5); 
    Assert.AreEqual(new Dollar(10), five.times(2)); 
    Assert.AreEqual(new Dollar(15), five.times(3)); 
} 

classe DollaroBug di test NUnit? Previsto <MyType> Ma era <MyType>

public class Dollar 
{ 
    private int amount; 

    public Dollar(int amount) 
    { 
     this.amount = amount; 
    } 

    public Dollar times(int multiplier) 
    { 
     return new Dollar(amount * multiplier); 
    } 

    public bool equals(Object theObject) 
    { 
     Dollar dollar = (Dollar) theObject; 

     return amount == dollar.amount; 
    } 
} 

on line Assert.AreEqual (nuova Dollar (10), five.times (2)); Test con errore:

attesi: TDDbooks.Dollar

Ma era: TDDbooks.Dollar

+0

a parte: perché non implementare l'overloading dell'operatore? –

+0

Sembra che potrebbe trattarsi di un problema di versione dell'assembly; è possibile che tu abbia due versioni dell'assembly che implementa 'TDDbooks.Dollar' caricato? –

risposta

4

NUnit visualizza la rappresentazione di stringa di oggetti. Al fine di avere a portata di mano in uscita, si dovrebbe ignorare ToString metodo Dollar classe:

public override string ToString() 
{ 
    return "$" + amount; 
} 

Ora output sarà simile:

Expected: $10 
But was: $10 

problema successivo è il confronto di dollari. NUnit confronta gli oggetti chiamando il metodo Equals (non equals, ma Equals. Kent Beck usa Java nei suoi esempi, in C# abbiamo i nomi Pascal per i metodi). L'implementazione predefinita del metodo Equals restituisce true se gli oggetti hanno lo stesso riferimento. Ma nel metodo Times si crea una nuova istanza della classe Dollar. Per risolvere questo problema, è necessario modificare l'implementazione del metodo Equals per confrontare il campo dell'importo.

public override bool Equals(object obj) 
{ 
    Dollar other = obj as Dollar; 
    if (other == null) 
    return false; 

    return amount == other.amount; 
} 

Notare inoltre, che si dovrebbe usare override parola chiave per la funzionalità di classe di base prevalente. E ancora una cosa: quando si ridefinisce la funzionalità Equals, è necessario eseguire l'override del metodo GetHashCode. Nel tuo caso è OK per avere qualcosa di simile:

public override int GetHashCode() 
{ 
    return amount.GetHashCode(); 
} 
+2

Inoltre, se si prevede di non derivare dalla classe 'Dollar', considerare di renderlo' sealed'. Se non lo rendi 'sealed', considera di dire' if (GetType()! = Other.GetType()) restituisce false; 'all'interno del metodo' Equals'. Altrimenti, si otterrebbe un cattivo risultato se "altro" è un "dollaro" di un tipo più derivato, come un "DescriptionDollar". –

11

Il metodo Assert.AreEquals utilizzerà il metodo di Equals per testare l'uguaglianza. Invece di sovrascrivere Object.Equals il tipo Dollar definisce solo un nuovo metodo equals che non partecipa all'uguaglianza di oggetti .Net. Quindi non viene utilizzato e il test utilizza l'uguaglianza di riferimento che non riesce. Per risolvere questo problema è necessario eseguire l'override del metodo

public override bool Equals(object obj) { 
    Dollar other = obj as Dollar; 
    if (other == null) { 
    return false; 
    } 

    return amount == other.amount; 
} 
0

Ci sono un paio di cose Object.Equals:

  1. Hai definito un nuovo metodo equals, anziché l'override del metodo della classe base Equals. Passa a ignorare e NUnit chiamerà il tuo metodo.
  2. NUnit stampa l'oggetto utilizzando il suo ToString e l'implementazione predefinita di ToString è semplicemente per stampare il nome della classe. Sostituire ToString per stampare l'importo e il messaggio di asserzione avrà molto più senso.
0

Ciò che stiamo affermando è che new Dollar(10) è lo stesso oggetto delle uno five.times(2) rendimenti, che non è vero.

Se si vuole affermarsi in quel modo ci si deve sovraccaricare il metodo Equals nella classe dollaro in questo modo:

public override bool Equals(Object obj) 
{ 
    if (obj is Dollar) 
    { 
     return this.Amount == ((Dollar)obj).Amount; 
    } 
    return false; 
} 

Non si utilizza la parola chiave override nel metodo Equals.

0

La soluzione migliore è già stata fornita da poche persone, ma esiste un'alternativa che potrebbe funzionare in altre situazioni. Avresti bisogno di aggiungere un getter per il campo amount in questo modo:

public int Amount { get { return amount; } } 

E poi, quando si fa il test di unità, sarebbe simile:

Assert.AreEqual(10, five.times(2).Amount); 

Così ora si sta confrontando un int a un altro int. In alternativa è possibile rendere pubblica la variabile amount, sebbene ciò interrompa l'incapsulamento. Ovviamente usare il metodo Equals correttamente è il modo migliore per andare in questo caso, ma in alcune situazioni, questo potrebbe essere preferibile.

Problemi correlati