测试并不只是测试工程师的责任,对于开发工程师,为了保证发布给测试环节的代码具有足够好的质量( Quality ),为所编写的功能代码编写适量的单元测试是十分必要的。
白盒测试:全面了解程序内部逻辑结构,对所有逻辑路径进行测试。
单元测试:对软件基本组成单元进行的测试,这里的单元是软件设计的最小单位,单元测试属于白盒测试范畴。
打桩:在做单元测试或者集成测试时,如果某个程序单元的某条语句需要调用的一个外部函数还没有完成的话,可以简单让它返回几个支持测试用例的值,这种状态的外部函数就是“打桩”。
单元测试( Unit Test ,模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确,通过编写单元测试可以在编码阶段发现程序编码错误,甚至是程序设计错误。
单元测试不但可以增加开发者对于所完成代码的自信,同时,好的单元测试用例往往可以在回归测试的过程中,很好地保证之前所发生的修改没有破坏已有的程序逻辑。因此,单元测试不但不会成为开发者的负担,反而可以在保证开发质量的情况下,加速迭代开发的过程。
将自己编写的代码创建生成一个动态库,并准备一个导出函数。如何创建一个动态库?可按照如下操作:
1)新建立一个空项目
2)解决方案管理器中为项目添加一个头文件,选择新建项
3)在新建的头文件中声明要导出的API,我添加一个简单的加和函数:
4)添加一个源文件,实现申明的API函数
#include "DLL.h"
int ADD(int a, int b)
{
return a + b;
}
5)修改项目-》项目属性-》常规-》配置类型为动态库(.DLL)
6)生成解决方案
生成解决方案,可以看到工程目录的debug目录或者release目录下(这取决你生成的是debug版本还是release版本)生成了动态链接库的相关文件。第三方调用时关键的文件为.lib文件和.dll文件以及工程目录下的.h头文件。
1)新建一个C/C++项目(test)
2)将第三方库的.h文件、.lib文件、.dll文件复制进工程项目中,.dll文件是程序运行需要载入的动态链接库,VS中调试时可以通过 项目->属性->调试->环境 栏目添加.dll文件的path而成功调试,但在独立运行.exe程序是须将.dll文件放到同一目录下,因此建议直接将.dll文件放入debug目录下或release目录下。.h头文件和.lib库文件可以随意放置,只要是能够通过路径找到即可,为了方便管理,建议建立文件夹,放置在项目目录下。
3)在项目中调用第三方库
有三种方法可以调用第三方库。
(1)直接在代码前添加引用
#include "../DLL/DLL.h" //通过相对路径或绝对路径添加头文件
#pragma comment (lib,"../DLL/DLL1.lib") //添加库文件
void main()
{
std::cout << ADD(3, 4) << std::endl;
}
(2)在解决方案管理面板中添加头文件和资源文件
添加一个现有项头文件,在文件夹中找到第三方库的头文件(DLL.h),添加进新建立的项目。
添加一个现有项资源文件,在文件夹中找到第三方库的库文件(DLL1.lib),添加进新建立的项目。
(3)在项目属性设置中添加头文件和库文件
项目->属性->VC++目录->包含目录 中添加第三方库的头文件;库目录下添加第三方库的库文件(.lib文件)。
项目->属性->链接器->输入->附加依赖项中输入库文件名称。
4.在函数中调用第三方库中的函数
void main()
{
std::cout << ADD(3, 4) << std::endl;
}
编译运行,结果符合预期。
在Solution中单击右键,创建新的单元测试工程。这里我们选择Native Unit Test Project.
工程名字可以随便写,暂时用默认的就可以。
工程创建完成够,整个solution的结构应该如下图所示:
其中在unittest1.cpp中是自动生成的单元测试模板。
为了能够让单元测试工程和我们创建的动态链接库工程关联上,我们需要做如下配置。
首先,让单元测试工程引用动态链接库工程。
然后再将动态链接库的代码路径加入到单元测试的Include Directories。
我们先简单看一下unittest1.cpp这部分代码。
namespace UnitTest1
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
// TODO: Your test code here
}
};
}
namespace UnitTest1 :
这个命名空间名字可以改,但是建议和文件名一致,这样方便以后看代码
TEST_CLASS(UnitTest1) :
这个宏设定单元测试的类的名称,单元测试的名字也尽量要可读。需要注意的是这是class的名字,需要符合class的命名规范
TEST_METHOD(TestMethod1) :
要测试的方法,名字也可以随便起,但是最好要和要测试的方法保持一致。比如要测试的方法叫做method,那么测试方法就叫TestMethod。
在编写测试代码时和正常编码并没有什么不同。单元测试的主要思想是通过给定输入以及预期的输出,来判断方法实现是否有问题。比如要测试一个求和函数,输入为1和2,那么预期输出是3。如果调用方法之后得到的结果不是3,那么这个测试用例就会失败,单元测试结果则为失败。
具体到我们这个测试,参照如下代码,输入参数是10,那么我们应该得到的结果是5,因为1到10之间共有5个奇数。(注意,不要忘记在unittest1.cpp中include动态链接库的头文件)
TEST_METHOD(TestMethod1)
{
Assert::AreEqual(getOddCount(10), 5);
}
在单元测试中,需要使用Assert这个类中的方法对结果进行判断,这样测试结果才会正确的反馈到IDE中。上面的代码中用到的是AreEqual方法,用于判断预期结果与方法调用后的结果是否相同。Assert类中有很多用于测试的方法,除了相等还有不等,真假等等,也有让测试强制失败的方法,可以根据具体的情况是使用。测试代码写完后,我们编译整个solution或者编译单元测试project,如果编译没有问题的话,就可以开始测试了。
在上一步中,如果没有编译问题的话,我们就可以在Test Explorer中看到现在所有的单元测试。注意,如果更新了单元测试代码,需要对project重新进行编译。通过菜单中的Test->Windows->Test Explorer可以打开Test Explorer。
在Test Explorer中点击Run All就会开始运行所有的单元测试。稍等一会,如果测试通过,就会有如下图显示:
这绿色看着真舒服(?)。如果测试未通过
让我们再修改一下我们的代码,让我们的getOddCount函数产生一点小小的错误…
int getOddCount(int number)
{
int nCount = 0;
for (int i = 2 i <= number; i++)
{
if (i % 2 != 0)
{
nCount++;
}
}
return nCount;
}
重新编译整个solution之后,再次重新运行所有的单元测试…
双击失败的单元测试,我们可以快速定位到出错的地方。
如果使用的时x64平台,可以会因为单元测试工程和目标工程的平台(x86和x64)不一致导致运行时错误,错误提示如下:
Make sure that test discoverer & executors are registered and platform & framework version settings are appropriate and try again.
这个时候只要通过菜单Test -> Test Settings -> Default Processor Architecture调整单元测试使用的CPU架构即可。
Google Mock是google推出的一个开源的白盒测试工具,可以配合Google Test来做C++的单元测试打桩。一个项目可能需要多个人来协作完成,在进行单元测试的时候,你可能并不关心你所调用的接口是如何实现的,只需要测试你的代码逻辑、接口是否调用以及传入的参数是否正确,这种情况下使用Google Mock进行单元测试非常合适。
https://blog.csdn.net/russell_tao/article/details/7333226
https://blog.csdn.net/weixin_42670653/article/details/81741814
https://blog.csdn.net/lionzl/article/details/8667003?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2