Moq - How to verify that a property value is set via the setter

前端 未结 5 1875
梦如初夏
梦如初夏 2020-12-16 09:22

Consider this class:

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


        
相关标签:
5条回答
  • 2020-12-16 09:22

    The following should work. Configure your mock object as:

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

    And after the test code:

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

    I haven't tested it anyway, so please tell me if it works for you.

    EDIT. Indeed, this will not work since the setter for IsCheckedOut is false.

    Anyway, now I see that you never set the value of IsCheckedOut at class construction time. It would be a good idea to add the following to the Content class:

    public Content()
    {
        IsCheckedOut=false;
    }
    
    0 讨论(0)
  • 2020-12-16 09:34
    Mock mockContect = new Mock<Cotent>(); 
    mockContent.VerifySet(x => x.IsCheckedOut, Times.Once());
    

    Will that do the trick? Not sure how the private setter comes in to play as havent tested that. but works for my public setter.

    Got this from: http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx

    0 讨论(0)
  • 2020-12-16 09:34

    why don't you simply set up the content to be checked out to start with? Remember, you are only testing the behaviour of the CheckIn function.

    [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);
    }
    
    0 讨论(0)
  • 2020-12-16 09:40

    Can I suggest that you might be thinking about this in the wrong way - generally you should be setting something up, performing an action and then checking the behaviour (result). In this case does it really matter that it wasn't set to false by the setter - what should matter is that it is false in after a given scenario has been exercised. If you take tests in isolation this might seem a bit odd, but for anything your tests will exist in sets.

    The situation would be different if you were testing the interaction between two classes - then it would be fine to set up an expectation on the property setter - as the setting action is the interaction you're testing.

    I'm not familiar with Moq as I use Rhino.Mocks - but I'm guessing there'll be something along the lines of mock.VerifySet(content => content.IsCheckedOut=It.IsEqual(true));

    0 讨论(0)
  • 2020-12-16 09:47

    I agree with you: mocking has no value in this scenario because it is intended to test the interactions between your class (under test) and the rest of the world, not to test the inner mechanism of your class.

    I think that this test

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

    that you write has sense and it is not a false positive! You must ensure that the state is in that way after the CheckIn regardless on why it is so; if in the future you will set the state in the constructor (or in other methods) this test will save you and you will be forced to implement the CheckIn method!

    In some cases similar to your I want to set the initial state to be sure that I does not forget to implement the CheckIn method; in this case I use 2 methods (the first is very ugly):

    1. I call c.CheckOut() before c.CheckIn(); this is very ugly, because you test 2 methods instead of one ... but I admit that I wrote something similar few times :-)
    2. I make the private setter protected, and I write a test class that inherits from the class under test; in this manner I can set the property to true before to call c.CheckIn() to ensure that the method is doing his job.

    Here it is the 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
        }
    }
    

    Hope to help.

    0 讨论(0)
提交回复
热议问题