2009-04-18 5 views
2

Ich habe einige grundlegende Klassen mit Klonierungsverfahren:Einheit einen Klon-Methode mit Moq in C# Testen

public class SimpleClass 
{ 
    public int ValueA { get; set; } 

    public string ValueB { get; set; } 

    public ulong ValueC { get; set; } 

    public SimpleClass TypedClone() 
    { 
     var item = new SimpleClass 
     { 
      ValueA = this.ValueA, 
      ValueB = this.ValueB, 
      ValueC = this.ValueC 
     }; 

     return item; 
    } 
} 

ich einen Komponententest wollen, die mir sagen, ob ich Valued hinzufügen, aber vergessen, es zu dem Klon hinzufügen Methode. Mein erster Versuch war, Moq und seine VerifyGet-Methode zu verwenden, um sicherzustellen, dass auf jede Eigenschaft zugegriffen wurde.

public void GenericCloneTest() 
    { 
     var mock = new Mock<SimpleClass>(); 
     var c = mock.Object.GenericClone(); 
     var properties = typeof(SimpleClass).GetProperties(); 

     foreach (var property in properties) 
     { 
      var expression = Expression.Property(
       Expression.Parameter(typeof(SimpleClass), "c"), 
       property); 

      var type = Expression.GetFuncType(typeof (SimpleClass), 
       property.PropertyType); 

      var actionExpression = Expression.Lambda(type, expression, 
       Expression.Parameter(typeof(SimpleClass), "c")); 

      mock.VerifyGet<object> 
       ((Expression<Func<SimpleClass,object>>)actionExpression); 
     } 
    } 

Das funktioniert nicht, weil die VerifyGet Methode des Rückgabetyp des Eigenschaftenaccessor wissen muss, und ich kann jede mögliche Weise nicht herausfinden, es zur Laufzeit einfügen (Sie werden meinen lahmen Versuch feststellen zu Verwenden Sie "Objekt", das abgestürzt und gebrannt hat).

Ich bin nicht einmal sicher, ob Moq eine gute Idee ist, es war nur meine erste.

UPDATE: Ohne eine schnelle und einfache generische Möglichkeit, eine Klonierungsmethode zu testen, entschied ich mich, typspezifische Tests für jede Klasse zu schreiben. Dies wirft immer noch das Problem auf, zu wissen, wann Eigenschaften hinzugefügt wurden. Ich ließ mich diese zu meinen Klon Unit-Tests auf anhängt:

 var signature = typeof (Connection) 
      .GetProperties() 
      .Select(p => p.Name) 
      .Aggregate(
       new StringBuilder(), 
       (builder, name) => 
        builder.Append(name)).ToString(); 

     Assert.AreEqual(
      "DataSessionStateDataTechnologyBytesReceivedBytesSentDuration", 
      signature); 

Wenn ich eine Eigenschaft der Test fehl hinzufügen. Es hängt immer noch davon ab, ob ich genug Verantwortung habe, um den Rest des Tests zu reparieren, wenn die Signaturübereinstimmung fehlschlägt.

Antwort

1

Eine der einfachsten Methoden, um sicherzustellen, dass Sie alle Ihre Felder erhalten, besteht darin, einfach die MemberwiseClone() - Methode zu verwenden. Dadurch werden automatisch alle Klassenfelder in die neue Instanz kopiert.

+0

Danke Paul! Ich dachte immer, dass etwas in .NET eingebaut sein müsste, aber es noch nicht gefunden hatte. Dies wird überall dort nützlich sein, wo ich eine schnelle seichte Kopie machen möchte. – MichaC

2

Sie möchten Moq hier nicht wirklich verwenden, Sie brauchen nur etwas Reflexion zu verwenden. Im Grunde schreibe einen Test, der eine Instanz deines Objekts erstellt, setzt jede Eigenschaft, klont sie und stellt dann sicher, dass jede Eigenschaft im Klon gleich ist. Wie Paul schon sagte, sehen Sie sich MemberwiseClone() an, das im Grunde genommen das für Sie tut oder zumindest ICloneable implementiert, was eine Standardpraxis dafür ist. (MemberwiseClone() erstellt nur eine flache Kopie, weshalb Sie möglicherweise ICloneable implementieren müssen). Dann könnten Sie sogar einen Test schreiben, der Ihre Baugruppe nach allem durchsucht, was ICloneable implementiert und testet.

+0

Ich fing an, darüber nachdenken, nur mit Reflexion, aber der schwierige Teil ist der Schritt, wo Sie "jede Eigenschaft festlegen." Ich muss jede Eigenschaft auf etwas anderes als den Standardwert setzen, um die Klon-Methode zu überprüfen, aber ich habe eine Sammlung von Eigenschaften mit einer beliebigen Anzahl von Typen. Ich muss Code schreiben, der weiß, wie man jeden möglichen Typ ändert und vergleicht. Die Frage ist, ob das mehr Arbeit ist, als nur einen eindeutigen Klontest für jeden Typ zu schreiben. – MichaC

+0

Ja, es ist ein Gleichgewicht der Komplexität in einem Test über viel zusätzlichen Code in mehreren Tests ... immer ein hartes Urteilsspruch. In diesem Fall würde ich jedoch einen komplexen Test durchführen, da Sie dadurch viele Wiederholungstests durchführen können. Sie könnten ein einfaches Wörterbuch oder eine switch-Anweisung mit verschiedenen Testwerten für die verschiedenen Datentypen erstellen. –

+0

Für den generischen Fall, in dem Ihr geklontes Objekt Objektreferenzen enthalten kann, ist dies eine sehr mühsame Sache, mit Reflexion zu codieren. Es reicht nicht aus, nur "jede Eigenschaft festzulegen", sondern Sie müssen sicherstellen, dass Sie auf etwas * anderes * als den Standardwert eingestellt haben. Mein Team ist diesen Weg einmal gegangen; Wir haben für jede Eigenschaft einen "zufälligen" Wert ausgewählt, der sich wiederholt, bis wir einen nicht-voreingestellten Wert erreicht haben. Dazu musste eine Methode programmiert werden, um einen "zufälligen" Wert für jeden möglichen Eigenschaftstyp zu geben, einschließlich unserer benutzerdefinierten Objekte! Es hat mehrere Stunden gedauert und war ein Alptraum zu verstehen und zu pflegen. –

Verwandte Themen