【发布时间】:2014-07-02 00:29:26
【问题描述】:
我正在尝试提出一个应该使用严格模拟的场景。我想不出来。
你什么时候使用严格的模拟,为什么?
【问题讨论】:
-
我经常读你的博客,所以我已经读过了。那篇文章向我保证我做得对:)
标签: unit-testing mocking tdd moq
我正在尝试提出一个应该使用严格模拟的场景。我想不出来。
你什么时候使用严格的模拟,为什么?
【问题讨论】:
标签: unit-testing mocking tdd moq
我有一个简单的约定:
当被测系统 (SUT) 将调用委托给底层模拟层时,使用严格模拟,而没有真正修改或将任何业务逻辑应用于传递给自身的参数。
当 SUT 将业务逻辑应用于传递给自身的参数并将一些派生/修改的值传递给模拟层时,请使用松散模拟。
例如:假设我们有数据库提供者 StudentDAL,它有两种方法:
数据访问接口如下所示:
Student GetStudentById(int id);
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.
}
【讨论】:
当您想要验证是否使用正确的参数调用了预期的方法时,可以使用普通(或松散)模拟。
严格的模拟用于验证仅调用了预期的方法,而没有调用其他方法。将它们视为一种负面测试。
在大多数情况下,严格的模拟会使您的单元测试非常脆弱。即使您对内部实现进行小的更改,测试也会开始失败。
但让我举个例子,它们可能有用 - 测试一个需求,例如:
“如果缓存中已包含数据,则获取缓存不应访问数据库”。
有一些方法可以通过松散的模拟来实现这一点,但相反,只需设置一个严格的 Mock<Database> 并期望函数调用为零就非常方便。对该数据库的任何调用都会引发异常并导致测试失败。
您想要使用严格模拟的另一种情况是Adapter 或Wrapper 设计模式。在这种模式中,您不会执行太多业务逻辑。测试这些类的主要部分是是否使用正确的参数(而不是其他参数)调用了底层函数。在这种情况下,严格的模拟效果相当好。
【讨论】: