【发布时间】:2012-04-04 09:21:40
【问题描述】:
例如,这句话是什么意思?
与外部 API 集成几乎是任何现代网络应用程序的保证。为了有效地测试这种集成,您需要存根它。一个好的 stub 应该易于创建,并且始终与实际的当前 API 响应保持同步。在这篇文章中,我们将概述使用 stubs 对外部 API 的测试策略。
【问题讨论】:
-
你看过What is a "Stub"?接受的答案了吗?
标签: terminology stub
例如,这句话是什么意思?
与外部 API 集成几乎是任何现代网络应用程序的保证。为了有效地测试这种集成,您需要存根它。一个好的 stub 应该易于创建,并且始终与实际的当前 API 响应保持同步。在这篇文章中,我们将概述使用 stubs 对外部 API 的测试策略。
【问题讨论】:
标签: terminology stub
存根是现有依赖项(或合作者)的可控替代品 在系统中。通过使用存根,您可以在没有 直接处理依赖关系。
外部依赖 - 现有依赖:
它是您系统中的一个对象,您的代码
under test 与您无法控制的交互。 (常见的
例如文件系统、线程、内存、时间等等。)
例如下面的代码:
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 类对象(现有依赖项对象)。
【讨论】:
stub,在此上下文中,表示模拟实现。
也就是说,一个符合接口并用于测试的简单假实现。
【讨论】:
通俗地说,在您(或另一方)准备好呈现/接收真实数据之前,您可以使用它来测试或开发代码的虚拟数据(或假数据、测试数据等)。这是程序员的“Lorem Ipsum”。
员工数据库还没准备好?与 Jane Doe、John Doe 等组成一个简单的组合。 API 还没准备好?通过创建一个包含假数据的静态 .json 文件来制作一个假的。
【讨论】:
在这个上下文中,“stub”这个词是用来代替“mock”的,但是为了清楚和精确起见,作者应该使用“mock”,因为“mock”是一种stub,但是供测试用。为避免进一步混淆,我们需要定义什么是存根。
在一般情况下,存根是一段程序(通常是函数或对象),它封装了调用另一个程序(通常位于另一台机器、VM 或进程上)的复杂性——但并非总是如此,它也可以是一个本地对象)。因为要调用的实际程序通常不在同一个内存空间上,所以调用它需要许多操作,例如寻址、执行实际的远程调用、编组/序列化要传递的数据/参数(与潜在结果相同),甚至可能处理身份验证/安全性等等。请注意,在某些情况下,存根也称为代理(例如 Java 中的动态代理)。
模拟是一种非常具体和限制性的存根,因为模拟是用于测试的另一个函数或对象的替代品。在实践中,我们经常使用 mocks 作为本地程序(函数或对象)来替换测试环境中的远程程序。在任何情况下,模拟都可以模拟被替换程序在受限上下文中的实际行为。
最著名的存根类型显然是用于分布式编程,当需要调用远程过程(RPC)或远程对象(RMI, CORBA)。大多数分布式编程框架/库会自动生成存根,因此您不必手动编写它们。存根可以从接口定义中生成,例如用IDL 编写(但您也可以使用任何语言来定义接口)。
通常,在 RPC、RMI、CORBA 等中,可以区分 客户端存根,它主要负责编组/序列化参数和执行远程调用,以及 服务器端存根,主要负责解组/反序列化参数并实际执行远程函数/方法。显然,客户端存根位于客户端,而服务器存根(通常称为骨架)位于服务器端。
在处理对象引用时,编写高效且通用的存根变得非常具有挑战性。大多数分布式对象框架(如 RMI 和 CORBA)都处理分布式对象引用,但大多数程序员在 REST 环境中避免这样做。通常,在 REST 环境中,JavaScript 程序员制作简单的存根函数来封装 AJAX 调用(JSON.parse 和 JSON.stringify 支持对象序列化)。 Swagger Codegen 项目为自动生成各种语言的 REST 存根提供了广泛的支持。
【讨论】:
Stub 是一个函数定义,它具有正确的函数名称、正确的参数数量并产生正确类型的虚拟结果。
它有助于编写测试并充当一种脚手架,即使在功能设计完成之前也可以运行示例
【讨论】:
这句话几乎可以肯定是与房屋建设阶段的类比——“拔管”管道。在施工过程中,在墙壁仍然敞开的情况下,将粗管道放入。这是继续施工所必需的。然后,当周围的一切都准备就绪时,一个人回来并添加水龙头和马桶以及实际的最终产品。 (例如参见How to Install a Plumbing Stub-Out。)
当你在编程中“存根”一个函数时,你构建了足够多的函数来解决问题(用于测试或编写其他代码)。然后,您稍后再回来并用完整的实现替换它。
【讨论】:
RPC 存根
【讨论】:
“删除一个函数意味着您只需编写足以表明该函数已被调用的内容,而将细节留到以后有更多时间时。”
来自:SAMS 自学 C++、Jesse Liberty 和 Bradley Jones
【讨论】:
Stub是一段在RPC(远程过程调用)过程中转换参数的代码。RPC的参数必须转换,因为客户端和服务器使用不同的地址空间。存根执行此转换,以便服务器将 RPC 视为本地函数调用。
【讨论】:
存根可以说是原始函数的假替代,它提供输出,由于以下原因,现在无法访问:
存根有:
为什么要使用存根?
当函数在测试等环境中无法访问,或者当它的实现不可用时。
示例:
假设你想测试一个有网络调用的函数。在测试代码时,您不能等待网络调用的结果来进行测试。所以你写了一个网络调用的模拟输出并继续你的测试。
TestFunction(){
// Some things here
// Some things here
var result = networkCall(param)
// something depending on the result
}
这个 networkCall 给出了一个字符串,所以你必须创建一个具有完全相同参数的函数,它应该给出字符串输出。
String fakeNetworkCall(int param){
if(param == 1) return "OK";
else return "NOT OK";
}
现在你已经编写了一个假函数,在你的代码中使用它作为替换
TestFunction(){
// Some things here
// Some things here
var result = fakeNetworkCall(param)
// something depending on the result
}
这个fakeNetworkCall 是一个存根。
【讨论】: