2015-08-11 20 views
5

Sto scrivendo Test unitari e sto pensando allo scenario di un tipo che implementa IClonable. Ovviamente voglio avere un test unitario che testa il metodo Clone().Test unitario: clone e uguaglianza

[Test] 
public void CloneObject() 
{ 
    MyType original = new MyType(); 
    MyType clone = (MyType)original.Clone(); 

    // Assert for equality 
} 

Quindi il mio primo compito è avere un Assert per l'uguaglianza. Vedo seguenti opzioni:

  • passando attraverso tutte le proprietà (campi) di MyType e controllare uno per uno
  • esclusione Equals() in MyType lasciare MyType dire se due istanze sono uguali (ritengo che a volte l'uguaglianza per le prove è considerato diverso dall'uguaglianza per il codice di produzione)
  • Verificare con un qualche tipo di serializzazione se le istanze sono uguali (per quello scenario MyType dovrebbe essere [Serializable], ma che a volte è difficile da fare se ha ad esempio Proprietà interfaccia)
  • ... ??

Per i primi due posso configurare i miei test e funzionano bene. Ma cosa succede se cambio MyType e aggiungo una proprietà aggiuntiva? Se Clone() non copia questo e non lo aggiungo nell'elenco delle proprietà controllate o il metodo equals il mio test passa ancora anche se la proprietà non viene copiata.

Come si risolve questo tipo di test?

+0

Avete considerato JSON (de) serializzazione o fa che soffrono le stesse limitazioni di serializzazione binaria ('[Serializable]') nella tua visualizzazione? –

risposta

5

È possibile utilizzare la libreria FluentAssertions (un TDD must-have, IMO), che ha un metodo ShouldBeEquivalent che esegue graph comparison dei due oggetti:

original.ShouldBeEquivalentTo(clone); 

L'algoritmo di confronto può essere personalizzato attraverso il cavo opzionale options parametro; vedere il loro wiki per informazioni dettagliate.

per rendere il futuro a prova di prova (ad esempio, si rompe quando nuove proprietà vengono aggiunte alla classe, ma non al metodo Clone), si potrebbe desiderare di provare la clonazione di un oggetto con tutte le sue proprietà impostate per caso valori non predefiniti. AutoFixture può farlo per te.

// Arrange 
var fixture = new Fixture(); 
var original = fixture.Create<MyType>(); 

// Act 
var clone = original.Clone(); 

// Assert 
clone.ShouldBeEquivalentTo(original); 

Link utili:

+0

Grazie! Questo funziona per me :) – joerg

+0

@joerg no prob! Assicurati di controllare cos'altro puoi fare con FluentAssertions: è pieno di chicche! – dcastro

+0

Oops ... un passo indietro ... Ho appena aggiunto un 'int' al mio tipo ... Avrei dovuto impostare un valore non predefinito nel mio test per fallire ... aggiungendo solo questa proprietà e il test passa ancora ... – joerg

0

ho favorirebbe Equals attuazione(). Non vedo alcun motivo per cui Equals() debba produrre risultati diversi nella produzione rispetto ai test.

Se non lo fai, il tuo Assert poteva chiamare object.ReferenceEquals(), come segue:

Assert.IsTrue(object.ReferenceEquals(expectedObject, objectInHand)); 
+0

Ho trovato la lettura [this] (http://blog.ploeh.dk/2012/06/22/Test-specificEqualityversusDomainEquality/) molto utile ... il ReferenceEquals dovrebbe Assert su false perché il clone dovrebbe avere un riferimento diverso da quello originale – joerg