web-dev-qa-db-de.com

Moq - So überprüfen Sie, ob ein Eigenschaftswert über den Setter eingestellt wird

Betrachten Sie diese Klasse:

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.
   }
}

Die Checkin-Methode ist absichtlich leer. Nun habe ich ein paar Testmethoden, um den Status der einzelnen Methoden zu überprüfen.

[TestMethod]
public void CheckOutSetsCheckedOutStatusToTrue()
{
    Content c = new Content();    
    c.CheckOut();
    Assert.AreEqual(true, c.IsCheckedOut); //Test works as expected
}

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

Der 2. Test besteht aus den falschen Gründen. Wie kann ich also mit Mocking (moq) überprüfen, ob das CheckIn die IsCheckedOut-Eigenschaft setzt?

Vielen Dank.

EDIT

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

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

Ich denke, meine Frage ist spezifisch. Wie kann ich überprüfen, ob die CheckIn () - Methode die IsCheckedOut-Eigenschaft auf false festgelegt hat? Dies würde ich Verhaltensüberprüfung nennen. 

Ich glaube, in einigen Kommentaren wurde vorgeschlagen, etwas zu tun, was einer Verifizierung des Staates gleichkommt. Wenn ja, glaube ich nicht, dass es einen Wert hat, diesen Teil überhaupt zu verspotten, wenn wir einfach Folgendes verwenden können:

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

Natürlich kann ich falsch liegen, also helfen Sie mir bitte, diese Konzepte zu klären :)

40
Anton P

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

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 sowieso nicht getestet, sagen Sie mir bitte, ob es für Sie funktioniert.

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

Wie auch immer, jetzt sehe ich, dass Sie niemals den Wert von IsCheckedOut zur Klassenbauzeit setzen. Es ist eine gute Idee, der Content-Klasse Folgendes hinzuzufügen:

public Content()
{
    IsCheckedOut=false;
}
38
Konamiman
Mock mockContect = new Mock<Cotent>(); 
mockContent.VerifySet(x => x.IsCheckedOut, Times.Once());

Wird das den Trick tun? Nicht sicher, wie der private Setter kommt, weil er das nicht getestet hat. aber arbeitet für meinen öffentlichen Setzer.

Hab das von: http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx

18
Dominic

warum richten Sie den Inhalt nicht einfach so ein, dass er ausgecheckt werden kann? 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);
}
4
Mark Heath

Darf ich vorschlagen, dass Sie falsch darüber nachdenken - im Allgemeinen sollten Sie etwas einrichten, eine Aktion ausführen und dann das Verhalten (Ergebnis) überprüfen. In diesem Fall spielt es wirklich eine Rolle, dass es vom Setter nicht auf "false" gesetzt wurde. Wichtig ist, dass es falsch ist, nachdem ein bestimmtes Szenario ausgeübt wurde. Wenn Sie Tests isoliert ablegen, mag dies etwas seltsam erscheinen, aber für alles, was Ihre Tests in Sets enthalten.

Die Situation wäre anders, wenn Sie die Interaktion zwischen zwei Klassen testen würden - dann wäre es gut, eine Erwartung für den Eigenschaftssetter festzulegen - da die Einstellungsaktion die Interaktion ist, die Sie testen.

Ich bin mit Moq nicht vertraut, da ich Rhino.Mocks verwende - aber ich schätze, es wird etwas in Richtung Mock.VerifySet geben (content => content.IsCheckedOut = It.IsEqual (true));

2
FinnNk

Ich stimme mit Ihnen überein: Spott hat in diesem Szenario keinen Wert, weil es beabsichtigt ist, die Wechselwirkungen zwischen Ihrer Klasse (im Test) und dem Rest der Welt zu testen, nicht den inneren Mechanismus Ihrer Klasse zu testen.

Ich denke das dieser Test 

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

dass du schreibst, hat Sinn und ist nicht falsch positiv! Sie müssen sicherstellen, dass sich der Status nach dem Einchecken in dieser Weise befindet, unabhängig davon, warum es so ist. Wenn Sie in Zukunft den Status im Konstruktor (oder in anderen Methoden) festlegen, werden Sie durch diesen Test gerettet, und Sie müssen die CheckIn-Methode implementieren.

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

  1. Ich rufe c.CheckOut () vor c.CheckIn () auf; das ist sehr hässlich, weil Sie testen 2 Methoden statt einer ... aber ich gebe zu, dass ich etwas ähnliches einige Male geschrieben habe :-)
  2. Ich mache den privaten Setter geschützt und schreibe eine Testklasse, die Von der zu testenden Klasse erbt; Auf diese Weise kann ich die-Eigenschaft vor dem Aufruf von c.CheckIn () auf true setzen, um sicherzustellen, dass die -Methode ihren Job erledigt.

Hier ist 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
    }
}

Hoffe zu helfen.

0