web-dev-qa-db-fra.com

Moq - Comment vérifier qu'une valeur de propriété est définie via le setter

Considérez cette classe:

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

La méthode Checkin est volontairement vide. Maintenant, j'ai quelques méthodes de test pour vérifier le statut d'appel de chaque méthode.

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

Le 2ème test réussit pour les mauvaises raisons. Alors, comment puis-je utiliser mocking (moq) pour vérifier que CheckIn définit la propriété IsCheckedOut?

Merci.

MODIFIER

Pour clarifier: j'ai une méthode appelée CheckIn () dont le travail consiste à définir le statut IsCheckedOut sur false. 

Vous verrez dans mon code de test ci-dessus que le test renverra false même si je ne mets pas la valeur de la propriété à false; Ceci est prévu, rien de mal ici.

Je pense que ma question est précisément: Comment puis-je vérifier que la méthode CheckIn () a défini la propriété IsCheckedOut sur false? C'est ce que j'appellerais une vérification comportementale. 

Je crois que certains des commentaires suggéraient de faire quelque chose qui équivaut à une vérification d’état? Si tel est le cas, je ne crois pas qu'il soit utile de se moquer de cette partie lorsque nous pouvons simplement utiliser:

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

Bien sûr, je peux me tromper, alors aidez-moi à clarifier ces concepts :)

40
Anton P

Ce qui suit devrait fonctionner. Configurez votre objet fictif comme suit:

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

Et après le code de test:

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

De toute façon, je ne l'ai pas encore testée, alors dites-moi si cela fonctionne pour vous.

MODIFIER. En effet, cela ne fonctionnera pas car le paramètre pour IsCheckedOut est faux.

Quoi qu'il en soit, je vois maintenant que vous ne définissez jamais la valeur de IsCheckedOut au moment de la construction de la classe. Ce serait une bonne idée d'ajouter ce qui suit à la classe Content:

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

Est-ce que ça va faire l'affaire? Je ne sais pas comment le passeur privé joue, car cela n’a pas été testé. mais travaille pour mon passeur public.

Vous l'avez obtenu à partir de: http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx

18
Dominic

pourquoi ne pas simplement configurer le contenu à vérifier pour commencer? N'oubliez pas que vous testez uniquement le comportement de la fonction CheckIn.

[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

Puis-je suggérer que vous pourriez penser à cela de la mauvaise façon - en général, vous devriez mettre en place quelque chose, effectuer une action puis vérifier le comportement (résultat). Dans ce cas, le fait qu’il n’ait pas été paramétré sur false n’est pas important - ce qui importe, c’est que c’est faux après l’exercice d’un scénario donné. Si vous prenez des tests isolément, cela peut sembler un peu étrange, mais dans tous les cas, vos tests existeront par jeux.

La situation serait différente si vous testiez l'interaction entre deux classes. Dans ce cas, il serait judicieux de définir une attente sur le configurateur de propriété. En effet, l'action de paramètre correspond à l'interaction que vous testez.

Je ne connais pas bien Moq car j'utilise Rhino.Mocks - mais je suppose qu'il y aura quelque chose du genre mock.VerifySet (content => content.IsCheckedOut = It.IsEqual (true));

2
FinnNk

Je suis d'accord avec vous: le moquage n'a aucune valeur dans ce scénario car il est destiné à tester les interactions entre votre classe (sous test) et le reste du monde, et non à tester le mécanisme interne de votre classe.

Je pense que ce test 

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

que vous écrivez a du sens et que ce n’est pas un faux positif! Vous devez vous assurer que l'état se trouve de cette manière après l'enregistrement, quelle qu'en soit la raison. Si, à l'avenir, vous définissez l'état dans le constructeur (ou dans d'autres méthodes), ce test vous enregistre et vous oblige à implémenter la méthode CheckIn!

Dans certains cas, similaires à votre, je souhaite définir l'état initial pour être sûr de ne pas oublier d'implémenter la méthode CheckIn; dans ce cas, j'utilise 2 méthodes (la première est très laide):

  1. J'appelle c.CheckOut () avant c.CheckIn (); c'est très moche, parce que. vous testez deux méthodes au lieu d'une ... mais j'avoue que j'ai écrit quelque chose de similaire. plusieurs fois :-)
  2. Je protège le setter privé et j'écris une classe de test qui hérite de la classe sous test; De cette manière, je peux définir la propriété sur true avant d'appeler c.CheckIn () afin de m'assurer que la méthode fait son travail.

Ici c'est le 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
    }
}

J'espère aider.

0
Daniele Armanasco