我读过各种关于测试中模仿和存根的文章,包括Martin Fowler的《Mocks Aren't Stubs》,但我仍然不理解其中的区别。
当前回答
存根是一个空函数,用于在测试期间避免未处理的异常:
function foo(){}
mock是一个人为的函数,用于避免在测试期间对操作系统、环境或硬件的依赖:
function foo(bar){ window = this; return window.toString(bar); }
在断言和状态方面:
在事件或状态更改之前断言模拟 存根不被断言,它们在事件之前提供状态,以避免执行来自不相关单元的代码 间谍就像存根一样被设置,然后在事件或状态改变后被断言 假的是不断言的,他们运行后的事件硬编码的依赖,以避免状态
参考文献
极客词汇:Mock 极客词汇:存根 极客术语:间谍 测试替身:假的,模拟和存根
其他回答
存根用于您在测试中设置的具有预期返回值的方法。 mock用于void方法,这些方法在调用时的Assert中进行验证。
Mock只是测试行为,确保调用了特定的方法。 Stub是特定对象的可测试版本(本质上)。
你说的苹果方式是什么意思?
Mock——Mock拦截对一个方法或函数的调用(或者像模拟类那样的一组方法和函数)。它不是该方法或函数的替代品。在那次拦截中,mock可以做任何它想做的事情,比如记录输入和输出,决定短路调用,更改返回值,等等。
存根——存根是一个有效的方法或函数(或一组方法和函数,就像存根类一样)的完整工作实现,它与它存根的方法、函数或一组方法和函数具有相同的接口/签名。stub实现通常只会做在单元测试上下文中可以接受的事情,这意味着它不会做IO,同时模仿它要stub的东西的行为。
Stub帮助我们运行测试。怎么做?它给出了有助于运行测试的值。这些值本身不是真实的,我们创建这些值只是为了运行测试。例如,我们创建一个HashMap来提供与数据库表中的值相似的值。因此,我们不直接与数据库交互,而是与Hashmap交互。
Mock是一个运行测试的伪对象。我们在这里输入assert。
假设你有一个名为EmployeeService的类,你想测试它,并且它对一个名为EmployeeDao的接口有一个依赖:
public class EmployeeService{
private EmployeeDao dao;
public EmployeeService(Dao dao){this.dao = dao;}
public String getEmployeeName(int id){
Employee emp = bar.goToDatabaseAndBringTheEmployeeWithId(id);
return emp != null?emp.getFullName:null;
}
//Further state and behavior
}
public interface EmployeeDao{
Employee goToDatabaseAndBringTheEmployeeWithId(int id);
}
在测试类内部:
public class EmployeeServiceTest{
EmployeeService service;
EmployeeDao mockDao = Mockito.mock(EmployeeDao.class);//Line 3
@Before
public void setUp(){
service = new EmployeeService(mockDao);
}
//Tests
//....
}
在上面的测试类的第3行中,我们对mock框架(在本例中是Mockito)说“嘿,Mockito,给我做一个具有EmployeeDao功能的对象。”框架将创建一个对象,它有goToDatabaseAndBringTheEmployeeWithId方法,但实际上没有主体。你的工作就是指导那个mock做什么。这是一个嘲弄。
但是你也可以创建一个实现EmployeeDao接口的类,并在测试类中使用它:
public EmployeeDaoStub implements EmployeeDao{
public Employee goToDatabaseAndBringTheEmployeeWithId(int id){
//No trip to DB, just returning a dummy Employee object
return new Employee("John","Woo","123 Lincoln str");
}
}
在你的测试类中,这次使用stub而不是mock:
public class EmployeeServiceTest{
EmployeeService service;
EmployeeDao daoStub = new EmployeeDaoStub();//Line 3
@Before
public void setUp(){
service = new EmployeeService(daoStub);
}
//Tests
//....
}
因此,为了包装这一切,存根是您(或其他人)专门创建的类,以模仿某些依赖关系,只是为了拥有所需的状态。是的,正如其他人所说,它主要是关于一个状态,而mock通常是由mock框架创建的,您不知道它的内部是什么样子的。但是使用存根,您知道将得到什么类:它是您创建的类。
哦,顺便说一下,如果你的依赖项是一个类而不是一个接口,你可以扩展这个类来创建你的存根。
推荐文章
- 比较Java中2个XML文档的最佳方法
- 如何模拟低带宽、高延迟的环境?
- 使用Moq验证方法调用
- 我如何“休眠”Dart程序
- 使用Mockito的泛型“any()”方法
- Mockito中检测到未完成的存根
- 尝试模拟datetime.date.today(),但不工作
- 如何用python timeit对代码段进行性能测试?
- 确定bash中是否存在一个函数
- 如何使用“测试”包打印Go测试?
- 如何在IntelliJ中为整个项目配置“缩短命令行”方法
- toBe(true) vs toBeTruthy() vs toBeTrue()
- 使用Mockito测试抽象类
- 什么时候应该使用Debug.Assert()?
- 使用Moq模拟扩展方法