单元测试:驱动模块和桩模块区别概念
传统的单元测试包括了驱动模块(driver) 和桩模块(stub)。驱动模块的目的很单纯,就是为了访问类库的属性和方法,来检测类库的功能是否正确;
驱动模块
驱动模块是用来模拟被测试模块的上一级模块,相当于被测模块的主程序。它接收数据,将相关数据传送给被测模块,启用被测模块,并打印出相应的结果。
驱动模块(Driver)可以通过模拟一系列用户操作行为,比如选择用户界面上的某一个选项或者按下某个按钮等,自动调用被测试模块中的函数。驱动模块(Driver)设置,使对模块的测试不必与用户界面真正交互。
桩模块
桩模块是指模拟被测试的模块所调用的模块,而不是软件产品的组成的部分。主模块作为驱动模块,与之直接相连的模块用桩模块代替。在集成测试前要为被测模块编制一些模拟其下级模块功能的“替身”模块,以代替被测模块的接口,接受或传递被测模块的数据,这些专供测试用的“假”模块称为被测模块的桩模块。
如果被测试的单元模块需要调用其他模块中的功能或者函数(method),我们就应该设计一个和被调用模块名称相同的桩模块来模拟被调用模块。这个桩模块本身不执行任何功能仅在被调用时返回静态值来模拟被调用模块的行为。举例说明:如果被测试单元中需要调用另一个模块customer的函数 getCustomerAddress(customerID: Integer),这个函数应该查询数据库后返回某一个客户的地址。我们设计的同名桩模块(Stub)中的同名函数并没有真正对数据库进行查询而仅模拟了这个行为,直接返回了一个静态的地址例如"123 Newton Street"。桩模块的设置使得单元测试的进行成为一个相对独立且简单的过程。
总结:
桩模块的使命除了使得程序能够编译通过之外,还需要模拟返回被代替的模块的各种可能返回值(什么时候返回什么值需要根据测试用例的情况来决定)。
驱动模块的使命就是根据测试用例的设计去调用被测试模块,并且判断被测试模块的返回值是否与测试用例的预期结果相符
单元测试:
在底层进行的对类/方法内部逻辑的测试叫做单元测试,也叫做模块测试。当单元测试的bug修复后,再把模块组合在一起构成子系统测试,这就是集成测试。集成测试的bug修复后各个子系统模块再组成整体业务流程的整套测试,这个过程叫做系统测试。
驱动模块:
驱动模块是用来模拟被测模块的上一级模块,相当于被测模块的主程序。它接收数据并将相关数据传送给被测模块,启用被测模块并打印出相应结果。驱动模块的目的很单纯,就是访问类库的属性和方法来确定类库是否正确。
桩模块:
桩模块是模拟被测试模块所调用的模块,而不是软件产品的组成部分。主程序作为驱动模块,与之直接相连的模块是桩模块,也称为“替身模块”。桩模块本身不执行任何功能,只在它作为替身被调用时返回静态值。
桩模块和驱动模块(以C语言为例):
很多人对桩模块和驱动模块的概念会搞不清楚,那么下面来介绍这两个概念:
模块结构实例图:
假设现在项目组把任务分给了7个人,每个人负责实现一个模块。你负责的是B模块,你很优秀,第一个完成了编码工作,现在需要开展单元测试工作,先分析结构图:
1、由于B模块不是最顶层模块,所以它一定不包含main函数(A模块包含main函数),也就不能独立运行。
2、B模块调用了D模块和E模块,而目前D模块和E模块都还没有开发好,那么想让B模块通过编译器的编译也是不可能的。
那么怎样才能测试B模块呢?需要做:
1、写两个模块Sd和Se分别代替D模块和E模块(函数名、返回值、传递的参数相同),这样B模块就可以通过编译了。Sd模块和Se模块就是桩模块。
2、写一个模块Da用来代替A模块,里面包含main函数,可以在main函数中调用B模块,让B模块运行起来。Da模块就是驱动模块。
知识点:
桩模块的使命除了使得程序能够编译通过之外,还需要模拟返回被代替的模块的各种可能返回值(什么时候返回什么值需要根据测试用例的情况来决定)。
驱动模块的使命就是根据测试用例的设计去调用被测试模块,并且判断被测试模块的返回值是否与测试用例的预期结果相符
驱动模块是调用被测对象,桩是被测对象调用的虚拟块
虚拟块也是有测试人员写的一个模块,就是那个所谓的桩
驱动模块是为了驱动被测模块而编写的模拟块,而桩模块相当于被测模块要调用的块的虚拟。
驱动模块主要完成以下事情:
1、接受测试输入;
2、对输入进行判断;
3、将输入传给被测单元,驱动被测单元执行;
4、接受被测单元执行结果,并对结果进行判断;
5、将判断结果作为用例执行结果输出测试报告。
被测单元用什么语言,驱动就用什么语言写。
总而言之,写驱动和桩不需要太高深编程知识。如果有模板或框架作为参考的话,差不多就成了一个体力活。
一个简单例子:
-
/*被测程序*/
-
int Fun(int in)
-
{
-
if (in >= 0)
-
{
-
return 1;
-
}
-
else
-
{
-
return -1;
-
}
-
}
那么通过TCL进行扩展指令编写时,针对该被测函数,驱动如下:
/*用户自己扩展的用户指令,用来驱动被测函数*/
-
int Ex_TestFun(ClientData clientData,Tcl_Interp * interp,int argc, char* argv[])
-
{
-
int i;
-
int ret,iExceptedRet;
-
//打开测试结果记录文件
-
FILE * out;
-
out = fopen("D:\\result.txt","a");
-
//第一步:检查用户输入参数个数是否正确
-
if (3 != argc)
-
{
-
fputs("Parameters error",out);
-
fflush(out);
-
return TCL_ERROR;
-
}
-
//第二步:取出用户输入参数
-
if (TCL_OK != Tcl_GetInt(interp,argv[1],&i))
-
{
-
return TCL_ERROR;
-
}
-
if (TCL_OK != Tcl_GetInt(interp,argv[2],&iExceptedRet))
-
{
-
return TCL_ERROR;
-
}
-
//第三步:将参数传递给被测函数
-
ret = Fun(i);
-
//第四步:将被测函数执行结果和输入的期望结果进行比较,根据比较结果作为用例执行结果输出到测试报告中
-
if (ret != iExceptedRet)
-
{
-
fputs("test fail",out);
-
fflush(out);
-
}
-
else
-
{
-
fputs("test success",out);
-
fflush(out);
-
}
-
return TCL_OK;
-
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!