考虑这个课程:
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
当然我可能错了,所以请帮我澄清这些概念:)
答案 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种方法(第一种非常难看):
这是代码:
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
}
}
希望能提供帮助。