在过去,我只使用了Rhino Mocks,典型的严格模拟。我现在正在与Moq合作开展一个项目,我想知道正确的用法。
假设我有一个带有方法Bar的对象Foo,它在对象Buzz上调用Bizz方法。
在我的测试中,我想验证Bizz是否被调用,因此我觉得有两种可能的选择:
严格模拟
var mockBuzz= new Mock<IBuzz>(MockBehavior.Strict);
mockBuzz.Setup(x => x.Bizz()); //test will fail if Bizz method not called
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.VerifyAll();
松散的模拟
var mockBuzz= new Mock<IBuzz>();
foo.Buzz = mockBuzz
foo.Bar();
mockBuzz.Verify(x => x.Bizz()) //test will fail if Bizz method not called
是否有标准或正常的方法?
答案 0 :(得分:76)
当我第一次在单元测试中使用模拟时,我曾经使用过严格的模拟。这不会持续很长时间。我停止这样做有两个原因:
由于这些原因,我强烈建议在单元测试中使用松散的模拟。
答案 1 :(得分:13)
我有C ++ /非.NET开发的背景,最近我更多地使用.NET,所以当我第一次使用Moq时,我有一定的期望。我试图理解WTF继续我的测试以及为什么我测试的代码抛出一个随机异常而不是Mock库告诉我代码试图调用哪个函数。所以我发现我需要打开严格的行为,这是令人困惑的 - 然后我遇到了这个问题,我看到的还没有勾选答案。
Loose 模式,以及它是默认 的事实是疯狂的 。 Mock库的重点是什么,它做了一些完全不可预测的事情,你还没有明确列出它应该做什么?
我完全不同意支持松散模式的其他答案中列出的要点。没有充分的理由使用它,我永远不会想要。在编写单元测试时,我想确定发生了什么 - 如果我知道函数需要返回null,我会让它返回。我希望我的测试变得脆弱(以重要的方式),以便我可以修复它们并添加到测试代码套件中的设置行,这些是明确的信息,它正在向我描述我的软件将会做什么。
问题是 - 是否有标准和正常的方式来做到这一点?
是的 - 从一般编程的角度来看,即其他语言和.NET世界之外,你应该始终使用Strict。善良知道为什么它不是Moq的默认值。
答案 2 :(得分:9)
我有一个简单的约定:
当被测系统(SUT)将调用委托给底层模拟层时,使用严格的模拟,而不是真正修改或应用传递给自身的参数的任何业务逻辑。
当SUT将业务逻辑应用于传递给自身的参数并将一些派生/修改的值传递给模拟层时,使用松散的模拟。
例如:
假设我们有数据库提供程序StudentDAL,它有两种方法:
数据访问界面如下所示:
public Student GetStudentById(int id);
public IList<Student> GetStudents(int ageFilter, int classId);
使用此DAL的实现如下所示:
public Student FindStudent(int id)
{
//StudentDAL dependency injected
return StudentDAL.GetStudentById(id);
//Use strict mock to test this
}
public IList<Student> GetStudentsForClass(StudentListRequest studentListRequest)
{
//StudentDAL dependency injected
//age filter is derived from the request and then passed on to the underlying layer
int ageFilter = DateTime.Now.Year - studentListRequest.DateOfBirthFilter.Year;
return StudentDAL.GetStudents(ageFilter , studentListRequest.ClassId)
//Use loose mock and use verify api of MOQ to make sure that the age filter is correctly passed on.
}
答案 3 :(得分:4)
我个人而言,不熟悉嘲笑和Moq认为从严格模式开始有助于更好地理解内部和正在发生的事情。 “松散”有时会隐藏细节并通过测试,而moq初学者可能无法看到。一旦你的模拟技能下降 - 松散可能会更有效率 - 就像在这种情况下使用“设置”保存一行,而只是使用“验证”。