Answers:
存根是系统中现有依赖项(或协作者)的可控替代。通过使用存根,您可以测试代码而无需直接处理依赖项。
外部依赖关系-现有依赖关系:
这是系统中的一个对象,您的被测试代码与之交互并且不受您控制。(常见的示例是文件系统,线程,内存,时间等。)
例如下面的代码:
public void Analyze(string filename)
{
if(filename.Length<8)
{
try
{
errorService.LogError("long file entered named:" + filename);
}
catch (Exception e)
{
mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
}
}
}
您想测试mailService.SendEMail()方法,但是要做到这一点,您需要在测试方法中模拟一个Exception,所以您只需要创建一个Fake Stub errorService对象来模拟您想要的结果,那么您的测试代码将是能够测试mailService.SendEMail()方法。如您所见,您需要模拟来自另一个依赖关系的结果,该另一个依赖关系是ErrorService类对象(现有依赖关系对象)。
一个存根,在此背景下,意味着一个模拟实现。
也就是说,一个简单,伪造的实现符合该接口并用于测试。
用Layman的术语来说,它是伪数据(或假数据,测试数据等),可用于测试或开发代码,直到您(或另一方)准备好呈现/接收真实数据为止。这是程序员的“ Lorem Ipsum”。
员工数据库尚未准备好?与Jane Doe,John Doe ...等组成一个简单的对象。API还没准备好吗?通过创建一个包含假数据的静态.json文件来组成一个假文件。
在这种情况下,用“存根”代替“模拟”,但是为了清楚和精确起见,作者应该使用“模拟”,因为“模拟”是一种存根,但用于测试。为了避免进一步的混乱,我们需要定义什么是存根。
在一般情况下,存根是一段程序(通常是一个函数或一个对象),它封装了调用另一个程序(通常位于另一个计算机,VM或进程上)的复杂性-但并非总是如此,它也可以是本地程序目的)。由于实际要调用的程序通常不在同一内存空间中,因此调用它需要很多操作,例如寻址,执行实际的远程调用,将要传递的数据/参数编组/序列化(以及可能的结果),甚至可能处理身份验证/安全性等等。请注意,在某些情况下,存根也称为代理(例如Java中的动态代理)。
模拟是一种非常特定且具有限制性的存根,因为模拟是用于测试的另一个函数或对象的替代。在实践中,我们经常将模拟程序用作本地程序(函数或对象),以替换测试环境中的远程程序。无论如何,模拟都可以在受限的上下文中模拟替换程序的实际行为。
当需要调用远程过程(RPC)或远程对象(RMI,CORBA)时,最著名的存根显然是用于分布式编程的。大多数分布式编程框架/库自动生成存根,因此您不必手动编写它们。可以从接口定义生成存根,例如,使用IDL编写(但您也可以使用任何语言来定义接口)。
通常,在RPC,RMI,CORBA等中,可以区分客户端存根和服务器端存根,客户端存根主要负责对参数进行编组/序列化并执行远程调用,而服务器端存根主要负责进行不编组/反序列化。参数并实际执行远程功能/方法。显然,客户端存根位于客户端,而服务器存根(通常称为框架)位于服务器端。
在处理对象引用时,编写高效且通用的存根变得非常具有挑战性。大多数分布式对象框架(例如RMI和CORBA)都处理分布式对象引用,但这是大多数程序员在REST环境中避免的事情。通常,在REST环境中,JavaScript程序员使用简单的存根函数来封装AJAX调用(JSON.parse
和支持对象序列化JSON.stringify
)。该扬鞭代码生成项目提供了各种语言的自动生成REST存根的广泛支持。
存根是一个函数定义,具有正确的函数名称,正确的参数数量并产生正确类型的伪结果。
它有助于编写测试,并且可以作为一种脚手架,使即使在功能设计完成之前也可以运行示例
RPC存根