Moq - 如何验证通过setter设置的属性值

时间:2009-10-29 06:24:27

标签: c# .net mocking tdd moq

考虑这个课程:

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

Checkin方法故意为空。现在我有一些测试方法来验证调用每个方法的状态。

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

第二次测试通过了错误的原因。那么我如何使用mocking(moq)来验证CheckIn是否设置了IsCheckedOut属性?

感谢。

修改

澄清一下:我有一个名为CheckIn()的方法,其工作是将IsCheckedOut状态设置为false。

您将在上面的测试代码中看到,即使我没有将属性值设置为false,Test也会返回false;这是预期的,这里没有错。

我认为我的问题具体是如何验证CheckIn()方法是否已将IsCheckedOut属性设置为false?这就是我所说的行为验证。

我相信有些意见建议做一些相当于国家核查的事情?如果是这样的话,当我们可以简单地使用时,我不相信嘲笑这部分有任何价值:

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

当然我可能错了,所以请帮我澄清这些概念:)

5 个答案:

答案 0 :(得分:39)

以下内容应该有效。将模拟对象配置为:

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

在测试代码之后:

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

我还没有测试过,所以请告诉我它是否适合你。

修改即可。实际上,由于IsCheckedOut的setter是假的,所以这不会起作用。

无论如何,现在我发现你从未在班级建设时设置IsCheckedOut的值。将以下内容添加到Content类:

是一个好主意
public Content()
{
    IsCheckedOut=false;
}

答案 1 :(得分:19)

Mock mockContect = new Mock<Cotent>(); 
mockContent.VerifySet(x => x.IsCheckedOut, Times.Once());

这会诀窍吗?不知道私人制定者是如何进行游戏的。但适用于我的公共制定者。

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

答案 2 :(得分:4)

为什么不简单地设置要检出的内容?请记住,您只是在测试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);
}

答案 3 :(得分:2)

我可以建议您以错误的方式考虑这个问题 - 通常您应该设置一些内容,执行操作然后检查行为(结果)。在这种情况下,设置者没有将它设置为false真的很重要 - 在给定的场景被执行之后它应该是错误的。如果您单独进行测试,这可能看起来有点奇怪,但对于任何测试都将存在于集合中。

如果您正在测试两个类之间的交互,情况会有所不同 - 那么在属性设置器上设置期望就可以了 - 因为设置操作是您正在测试的交互。

我不熟悉Moq,因为我使用的是Rhino.Mocks - 但我猜测会有类似于mock.VerifySet(content =&gt; content.IsCheckedOut = It.IsEqual(true))的内容。 ;

答案 4 :(得分:0)

我同意你的观点:在这种情况下,模拟没有价值,因为它旨在测试你的类(测试中)和世界其他地方之间的交互,而不是测试你的类的内部机制。

我认为这个测试

Content c = new Content();    
c.CheckIn();    
Assert.AreEqual(false, c.IsCheckedOut); //State verification
你写的有意义而且不是误报!你必须确保在CheckIn之后状态是这样的,不管为什么会这样;如果将来你将在构造函数中设置状态(或者在其他方法中),这个测试将保存你,你将被迫实现CheckIn方法!

在某些情况下,我想设置初始状态,以确保我不会忘记实现CheckIn方法;在这种情况下,我使用2种方法(第一种非常难看):

  1. 我在c.CheckIn()之前调用c.CheckOut();这非常难看,因为 你测试了两种方法而不是一种...但我承认我写了类似的东西 几次: - )
  2. 我保护私有的setter,我写了一个测试类 继承自被测试的班级;以这种方式我可以设置 属性为true之前调用c.CheckIn()来确保 方法正在完成他的工作。
  3. 这是代码:

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

    希望能提供帮助。