2009-10-29 4 views
31

Betrachten Sie diese Klasse:Moq - Wie zu überprüfen, ob ein Eigenschaftswert über die Setter gesetzt

public class Content 
{  
    public virtual bool IsCheckedOut {get; private set;} 
    public virtual void CheckOut() 
    { 
     IsCheckedOut = true; 
    } 

    public virtual void CheckIn() 
    { 
     //Do Nothing for now as demonstrating false positive test. 
    } 
} 

Der Checkin Methode ist absichtlich leer. Jetzt habe ich ein paar Testmethoden, um den Status des Aufrufs jeder Methode zu überprüfen.

Der 2. Test besteht aus den falschen Gründen. Also, wie kann ich Spott (Moq) verwenden, um zu überprüfen, dass CheckIn die IsCheckedOut-Eigenschaft setzt?

Danke.

EDIT

Zur Klarstellung: Ich habe eine Methode namens CheckIn(), deren Aufgabe es ist, den IsCheckedOut Status auf false gesetzt.

Sie werden in meinem Testcode oben sehen, dass der Test false zurückgibt, auch wenn ich den Eigenschaftswert nicht auf false setze; Das wird erwartet, hier ist nichts falsch.

Ich denke meine Frage speziell ist Wie kann ich überprüfen, dass die CheckIn() -Methode die IsCheckedOut -Eigenschaft auf false gesetzt hat? Dies würde ich als Verhaltensüberprüfung bezeichnen.

Ich glaube, einige der Kommentare vorgeschlagen, etwas zu tun, die staatliche Überprüfung bedeutet? Wenn so glaube ich nicht, dass es einen Wert gibt, diesen Teil überhaupt in spöttisch, wenn wir einfach nutzen:

Content c = new Content();  
c.CheckIn();  
Assert.AreEqual(false, c.IsCheckedOut); //State verification 

Natürlich kann ich falsch sein, so wenden Sie sich bitte helfen Sie mir, diese Konzepte zu klären :)

+0

Es hängt wirklich vom Zweck der IsChecked out-Eigenschaft ab - wenn es ein Verhalten des Objekts ist, dass nachdem etwas eingecheckt und dann ausgecheckt wurde, falsch ist, dann ist das, was Sie oben haben, in Ordnung. Wenn die Eigenschaft ein Fenster in Ihrer Klasse ist, um ein größeres Verhalten zu überprüfen, würde ich das als Zustandsüberprüfung bezeichnen. Also ... hängt wirklich von der Absicht ab. – FinnNk

+0

Dies schien das Problem zu lösen: http://stackoverflow.com/questions/2853313/moq-how-to-correctly-mock-set-only-properties –

+0

Ist die Frage nicht direkt beantworten, aber ich muss überprüft werden, dass eine Eigenschaft explizit auf "true" gesetzt wurde: 'mock.SetupProperty (foo => foo.SomeProperty);/* Testaktionen ausführen * /; mock.VerifySet (foo => foo.SomeProperty = It.IsAny (), "SomeProperty sollte gesetzt sein"); Assert.True (mock.Object.SomeProperty, "SomeProperty sollte auf true gesetzt worden sein"); ' –

Antwort

33

Folgendes sollte funktionieren. Konfigurieren Sie Ihr Mock-Objekt wie:

var mock=new Mock<IContent>(); 
mock.SetupSet(content => content.IsCheckedOut=It.IsAny<bool>()).Verifiable(); 

Und nach dem Testcode:

mock.VerifySet(content => content.IsCheckedOut=It.IsAny<bool>()); 

Ich habe es nicht ohnehin getestet, so wenden Sie sich bitte mir sagen, ob es für Sie arbeitet.

BEARBEITEN. In der Tat wird dies nicht funktionieren, da der Setzer für IsCheckedOut falsch ist.

Wie auch immer, jetzt sehe ich, dass Sie nie den Wert von IsCheckedOut zur Klasse Bauzeit setzen. Es wäre eine gute Idee sein, die folgenden auf die Content Klasse hinzuzufügen:

public Content() 
{ 
    IsCheckedOut=false; 
} 
+0

Zur Verdeutlichung.Ich möchte den Setter nicht auf der IsCheckedOut-Eigenschaft testen, stattdessen möchte ich testen, dass die Methode CheckIn() IsCheckedOut gesetzt hat = false; Außerdem ist die IsCheckedOut-Eigenschaft privat, daher glaube ich nicht, dass das Setup funktioniert. Ist es überhaupt möglich mit dem was ich machen möchte? Noch mehr Ideen? –

+0

IsCheckedOut ist in Ihrer Schnittstelle, so kann es nicht privat sein? – FinnNk

+0

FinnNk: nur der Getter ist in der Schnittstelle, der Setter ist privat. – Konamiman

2

Kann ich vorschlagen, dass Sie in dem falschen Weg, um dies könnten denken - in der Regel sollten Sie etwas wurden Einstellung, eine Aktion auszuführen und dann Überprüfen des Verhaltens (Ergebnis). In diesem Fall ist es wirklich wichtig, dass es vom Setter nicht auf "falsch" gesetzt wurde - was wichtig ist, ist, dass es falsch ist, nachdem ein gegebenes Szenario ausgeübt wurde. Wenn Sie Tests isoliert durchführen, mag das ein bisschen seltsam erscheinen, aber für alles, was Sie testen, wird es in Sätzen existieren.

Die Situation wäre anders, wenn Sie die Interaktion zwischen zwei Klassen testen würden - dann wäre es in Ordnung, eine Erwartung für den Property Setter zu erstellen - da die Einstellungsaktion die Interaktion ist, die Sie testen.

Ich bin nicht vertraut mit Moq, wie ich Rhino.Mocks - aber ich vermute, es wird etwas in der Form von mock.VerifySet (content => content.IsCheckedOut = It.IsEqual (true)) ;

+0

Bitte sehen Sie meinen bearbeiteten Post :) –

4

Warum richten Sie nicht einfach den Inhalt ein, der am Anfang ausgecheckt werden soll? Denken Sie daran, dass Sie nur das Verhalten der CheckIn-Funktion testen.

[TestMethod] 
public void CheckInSetsCheckedOutStatusToFalse() 
{ 
    // arrange - create a checked out item 
    Content c = new Content(); 
    c.CheckOut(); 

    // act - check it in 
    c.CheckIn(); 

    // assert - IsCheckedOut should be set back to false 
    Assert.AreEqual(false, c.IsCheckedOut); 
} 
+2

Ich stimme zu, dass die Verwendung eines Mock (ing Framework) in diesem Fall nicht notwendig erscheint. Diese vorgeschlagene Methode ist besser, da sie die öffentliche Schnittstelle statt interner Details testet (d. H. Wie die Eigenschaft festgelegt wird). – Cellfish

0

Ich stimmen Sie zu: spöttische keinen Wert in diesem Szenario hat, weil sie die Wechselwirkungen zwischen Ihrer Klasse zu testen (im Test) und der Rest der Welt bestimmt ist, nicht zu testen der innere Mechanismus deiner Klasse.

Ich denke, dass dieser Test

Content c = new Content();  
c.CheckIn();  
Assert.AreEqual(false, c.IsCheckedOut); //State verification 

, die Sie Sinn schreiben, und es ist nicht falsch positiv! Sie müssen sicherstellen, dass der Status auf diese Weise nach dem CheckIn angezeigt wird, unabhängig davon, warum dies der Fall ist. Wenn Sie in der Zukunft den Status im Konstruktor (oder in anderen Methoden) setzen, wird dieser Test Sie speichern und Sie werden gezwungen sein, die CheckIn-Methode zu implementieren!

In einigen Fällen möchte ich den Anfangszustand festlegen, um sicherzustellen, dass ich nicht vergessen, die CheckIn-Methode zu implementieren; In diesem Fall verwende ich 2 Methoden (die erste ist sehr hässlich):

  1. Ich rufe c.CheckOut() vor c.CheckIn(); das ist sehr hässlich, weil Sie 2 Methoden testen statt einem ... aber ich gebe zu, dass ich etwas ähnliches paar Male :-)
  2. schrieb ich die privaten Setter geschützt zu machen, und ich schreibe eine Test-Klasse, die inherits aus der getesteten Klasse; Auf diese Weise kann ich die Eigenschaft auf True setzen, bevor ich c.CheckIn() aufrufen kann, um sicherzustellen, dass die -Methode ihre Aufgabe erfüllt.

Hier ist es der Code:

public class Content2 
{ 
    public virtual bool IsCheckedOut { get; protected set; } 
    public virtual void CheckOut() 
    { 
     IsCheckedOut = true; 
    } 

    public virtual void CheckIn() 
    { 
     //Do Nothing for now as demonstrating false positive test. 
    } 
} 

    [TestClass] 
public class Content2Test : Content2 
{ 
    [TestMethod] 
    public void CheckOutSetsCheckedOutStatusToTrue() 
    { 
     this.CheckOut(); 
     Assert.AreEqual(true, this.IsCheckedOut); //Test works as expected 
    } 

    [TestMethod] 
    public void CheckInSetsCheckedOutStatusToFalse() 
    { 
     this.IsCheckedOut = true; 
     this.CheckIn(); 
     Assert.AreEqual(false, this.IsCheckedOut); //Test does not work as expected 
    } 
} 

Hoffnung zu helfen.

Verwandte Themen