博客目标:
1、搭建GTEST单元测试环境
2、对已有的一个项目进行单元测试,测试内容 函数、类的公/私有方法
单元测试开始之前,要先明确几个基本的概念,GTEST的单元测试实际上就是再单独创建一个工程,然后include待测试的函数/类,完成一些特定的测试功能,从这一点上来说,使用GTEST进行单元测试与自己创建空的工程调用待测函数完成一些测试功能是一样的。GTEST的优点在于提供了一些有用的测试函数,让我们在测试的时候不需要花费太多的精力去构造这些测试函数。
第一步,搭建GTEST测试环境
首先要到github上去下GTEST的源码,GTEST仓库地址,下载的时候注意分支的选择以及版本的选择,新的GTEST版本在早期的VS中是无法编译的,我现在用的GTEST是v1.8.x分支中的release_1.7.0版本,VS用的是2008.
下载下来之后,找到上面红框中的路径,打开gest.sln这个解决方案,在VS中对整个方案进行debug以及release两种方式的编译,并将编译的lib文件以及头文件拷贝到一个你自己觉得引用起来方便的位置,以下是我的操作结果。
在测试工程的特性中单独添加头文件(c/c++ -general - addtional path)以及lib依赖(linker - input - addtioanl path),但是要注意的是添加lib的时候,路径要写到具体的文件名,如C:\gtestLib \gtestd.lib,否则也会找不到链接。
同时不要忘了修改这个玩意,忘了的话也会报一堆链接错误。
完成以上,就完成了GTEST的搭建。
第二步,对已经有的一个项目中的函数以及类进行单元测试。
上图中,在sln中本身存在一个工程helloWorldForUnitest ,在工程中本身有addClass一个类,addFunc一个函数。为了对这两个文件中的内容进行测试,我又新建了一个unitTestDemo的工程,并在工程属性-C/C++-general-addtional path中添加了helloWorldForUnitest中头文件所在的路径,以使测试工程能够调用到待测函数,并右键add - an exist item添加了这两个头文件对应的cpp文件。
给出以上文件的代码
addClass.h,声明了一个类(声明类的时候,类块结束的时候一定要有分号做结尾,否则编译时候会报:构造函数返回值错误),包含公有方法以及私有方法。
#ifndef ADDCLASS_H
#define ADDCLASS_H
#include "forcePublic.h"
class addClass{
public:
addClass();
~addClass();
int getInput(int a,int b);
int getResult();
private:
int addMethod(int a,int b);
private:
int ma;
int mb;
int mResult;
};
#endif
addClass.cpp,实现了上面文件中声明的类。
#include "addClass.h"
#include <stdio.h>
addClass::addClass()
{
ma = 0;
mb = 0;
mResult = 0;
}
addClass::~addClass()
{
}
int addClass::getInput(int a,int b)
{
ma = a;
mb = b;
addClass::addMethod( a, b);
return 0;
}
int addClass::getResult()
{
return mResult;
}
int addClass::addMethod(int a,int b)
{
mResult = a + b;
return mResult;
}
forcePublic.h,一系列的宏定义用以完成测试过程中私有化方法转成公有方法的功能,方便测试工程对类中的私有方法进行访问。
#ifndef FORCEPUBLIC_H
#define FORCEPUBLIC_H
#define GTEST
#ifdef GTEST
#define private public
#define protected public
#endif
#endif
addFunc.h,声明了一个方法
# ifndef ADDFUNC_H
# define ADDFUNC_H
int addFunc(int a,int b);
# endif
addFunc.cpp,实现了上面文件中声明的方法
# include "addFunc.h"
int addFunc(int a,int b)
{
int c = a + b;
return c;
}
test1.cpp,用于对上面的类和方法进行测试
#include <gtest/gtest.h>
#include <tchar.h>
#include "addFunc.h"
#include "addClass.h"
int Foo(int a, int b)
{
if (a == 0 || b == 0)
{
throw "don't do that";
}
int c = a % b;
if (c == 0)
return b;
return Foo(b, c);
}
TEST(FooTest, HandleNoneZeroInput)
{
EXPECT_EQ(2, Foo(4, 10));
EXPECT_EQ(6, Foo(30, 18));
}
TEST(addFuncTest, HandleNoneZeroInput)
{
EXPECT_EQ(14, addFunc(4, 10));
EXPECT_EQ(48, addFunc(30, 18));
}
TEST(addClassTest,HandleNoneZeroInput)
{
int addorResult;
addClass addor;
addor.getInput(4,12);
addorResult = addor.getResult();
EXPECT_EQ(16,addorResult);
// private member test
EXPECT_EQ(100,addor.addMethod(1,99));
}
int _tmain(int argc, _TCHAR* argv[])
{
testing::InitGoogleTest(&argc, argv);
RUN_ALL_TESTS();
getchar();
return RUN_ALL_TESTS();
}
完成以上内容后,编译unitTestDemo工程,然后调试得到以下运行结果,证明你的第一个GTEST单元测试成功了。
PS:补充一些GTEST函数原型
// ***************************API index************************************//
//-------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
//ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_EQ(expected, actual); EXPECT_EQ(expected, actual); expected == actual
//ASSERT_NE(val1, val2); EXPECT_NE(val1, val2); val1 != val2
//ASSERT_LT(val1, val2); EXPECT_LT(val1, val2); val1 < val2
//ASSERT_LE(val1, val2); EXPECT_LE(val1, val2); val1 <= val2
//ASSERT_GT(val1, val2); EXPECT_GT(val1, val2); val1 > val2
//ASSERT_GE(val1, val2); EXPECT_GE(val1, val2); val1 >= val2
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); the two C strings have the same content
//ASSERT_STRNE(str1, str2); EXPECT_STRNE(str1, str2); the two C strings have different content
//ASSERT_STRCASEEQ(expected_str, actual_str); EXPECT_STRCASEEQ(expected_str, actual_str); the two C strings have the same content, ignoring case
//ASSERT_STRCASENE(str1, str2); EXPECT_STRCASENE(str1, str2); the two C strings have different content, ignoring case
//------------------------------------------------------------------------//
//Fatal assertion Nonfatal assertion Verifies
//ASSERT_THROW(statement, exception_type); EXPECT_THROW(statement, exception_type); statement throws an exception of the given type
//ASSERT_ANY_THROW(statement); EXPECT_ANY_THROW(statement); statement throws an exception of any type
//ASSERT_NO_THROW(statement); EXPECT_NO_THROW(statement); statement doesn't throw any exception
//
//class myTest : public::testing::TestWithParam<int> {
// };
//
// TEST_P(myTest, aLotTest) {
// int n = GetParam();
// EXPECT_TRUE(func (n));
// }
//
//INSTANTIATE_TEST_CASE_P(PreName, myTest, testing::Values(1, 10, 100, 1000, 10000));