天天看点

C++ 项目之Googletest单元测试

原创 lightcity 光城 2019-09-17收录于话题#C++那些事53个

C++ 项目之Googletest单元测试

1.Clion集成Googletest单元测试

Googletest - Google Testing and Mocking Framework

源码下载地址:

https://github.com/google/googletest/releases

Googletest中包含两个模块,分别是gtest与gmock,需要分别源码编译,编译完后,到指定目录去拷贝includes文件夹与.so文件到下面路径的指定位置.

然后项目中创建ext目录,里面分为两块

  • 第一块:includes

包含gmock与gtest的include文件,对应于gcc -I参数,头文件路径,包含以.h结尾的头文件

  • 第二块:libs

包含gmock与gtest的libs文件,对应gcc -L参数,库文件路径,里面包含的是一些.so或.dll等动态或静态链接库

├── ext
│   ├── includes
│   │   ├── gmock
│   │   └── gtest
│   └── libs
│       ├── gmock
│       └── gtest      

上述本地项目路径配置好后,在CmakeLists.txt中进行配置:

# ext
set(BASE_INCLUDES ext/includes)
set(BASE_LIBS ext/libs)

# googletest
set(GTEST_INCLUDE_DIR ${BASE_INCLUDES}/gtest/include)
set(GMOCK_INCLUDE_DIR ${BASE_INCLUDES}/gmock/include)
set(GTEST_LINK_DIR ${BASE_LIBS}/gtest/lib/)
set(GMOCK_LINK_DIR ${BASE_LIBS}/gmock/lib/)

# 去哪里找头文件 相当于gcc/clang 中的-I(i的大写字母)参数
include_directories(${GTEST_INCLUDE_DIR})
include_directories(${GMOCK_INCLUDE_DIR})

# 去哪里找库文件 .so .dll .dylib 相当于gcc 中的-L参数
link_directories(${GTEST_LINK_DIR})
link_directories(${GMOCK_LINK_DIR})      

然后为每个test配上链接库即可.

例如,现在有个测试file,文件名为:了l1.cpp

那么在CmakeLists.txt中配置为:

add_executable(l1 l1.cpp)
target_link_libraries(l1 gtest gtest_main)        

2.gtest之Helloworld

int main(int argc, char* argv[])
{
  // 接收命令行参数
  testing::InitGoogleTest(&argc, argv);
  vector<int> x={1,2,3,5};
  // EXPECT_EQ使用
  for (int i = 0; i < x.size(); ++i)
  {
      EXPECT_EQ(x[i], 1) << "Vectors x and y differ at index " << i;
  }
  RUN_ALL_TESTS();
 
  return 0;
}      

例如上述就是个完整的例子,每次运行:

testing::InitGoogleTest(&argc, argv);      

然后使用:

RUN_ALL_TESTS();      

运行所有的Test,每个Test编写参考后面断言.

我们看看运行效果:

l1.cpp:113: Failure
Expected equality of these values:
 x[i]
   Which is: 2
 1
Vectors x and y differ at index 1
l1.cpp:113: Failure
Expected equality of these values:
 x[i]
   Which is: 3
 1
Vectors x and y differ at index 2
l1.cpp:113: Failure
Expected equality of these values:
 x[i]
   Which is: 5
 1
Vectors x and y differ at index 3
[==========] Running 0 tests from 0 test cases.
[==========] 0 tests from 0 test cases ran. (0 ms total)
[  PASSED ] 0 tests.
[  FAILED ] 0 tests, listed below:

0 FAILED TESTS      

3.gtest初识之断言

关于断言Google包装了一系列

EXPECT

ASSERT

的宏,而EXPECT系列和ASSERT系列的区别是:

  • EXPECT

     失败时,案例继续往下执行。
  • ASSERT

    失败时,直接在当前函数中返回,当前函数中

    ASSERT

    后面的语句将不会执行。

例如:

TEST(ASSERTTest, ASSERT_VS_EXPECT)
{
   ASSERT_TRUE(10<2);  // ASSERT失败,直接在当前函数中返回,后面语句不执行
   ASSERT_FALSE(10<2);
   EXPECT_EQ(6, Foo(310, 18));
}      

每个Test是个宏,Test底层源码如下:

# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)      

对应test_case名与test名.

上述代码中10<2为False,而使用了

ASSERT_TRUE

,该Test后面所有内容就不会执行,如果换成

EXPECT_TRUE

则正常运行!

布尔值检查
Fatal assertion Nonfatal assertion Verifies

ASSERT_TRUE(

condition

)

;

EXPECT_TRUE(

)

condition is true

ASSERT_FALSE(

)

EXPECT_FALSE(

)

condition is false
数值型数据检查

ASSERT_EQ(

expected

,

actual

);

EXPECT_EQ(

,

);

expected 

==

 actual

ASSERT_NE(

val1

,

val2

);

EXPECT_NE(

,

);

val1 

!=

 val2

ASSERT_LT(

,

);

EXPECT_LT(

,

);

<

ASSERT_LE(

,

);

EXPECT_LE(

,

);

<=

ASSERT_GT(

,

);

EXPECT_GT(

,

);

>

ASSERT_GE(

,

);

EXPECT_GE(

,

);

>=

字符串检查
TEST(StringCmpTest, Demo)
{
   char* pszCoderZh = "CoderZh";
   wchar_t* wszCoderZh = L"CoderZh";
   std::string strCoderZh = "CoderZh";
   std::wstring wstrCoderZh = L"CoderZh";

   EXPECT_STREQ("CoderZh", pszCoderZh);
   EXPECT_STREQ(L"CoderZh", wszCoderZh);

   EXPECT_STRNE("CnBlogs", pszCoderZh);
   EXPECT_STRNE(L"CnBlogs", wszCoderZh);

   EXPECT_STRCASEEQ("coderzh", pszCoderZh);
   //EXPECT_STRCASEEQ(L"coderzh", wszCoderZh);   不支持

   EXPECT_STREQ("CoderZh", strCoderZh.c_str());
   EXPECT_STREQ(L"CoderZh", wstrCoderZh.c_str());
}      

其中STREQ和STRNE同时支持char和wchar_t类型的,STRCASEEQ和STRCASENE却只接收

char*

显示返回成功或失败

直接返回成功:

SUCCEED();

返回失败:

FAIL();

ADD_FAILURE();

// 返回成功与否
TEST(ExplicitTest, Demo)
{
   ADD_FAILURE() << "这行打印失败 Sorry"; // None Fatal Asserton,继续往下执行。

   //FAIL(); // Fatal Assertion,不往下执行该案例。
   EXPECT_TRUE(1==2)<<"1==2 failed!";      // 为了验证上述失败后是否执行下面

   SUCCEED();
}      
异常检查

分为三个:

EXPECT_NO_THROW(statement);

 不抛出异常

EXPECT_ANY_THROW(statement);

抛出任意类型异常

EXPECT_THROW(statement, exception_type);

抛出指定类型异常

TEST(ExceptionTest,et) {
   // 抛出任意类型异常
   EXPECT_ANY_THROW(10/0); //Expected: 10/0 throws an exception.
   // 抛出指定类型异常
   EXPECT_THROW(1/0,int); //Expected: 1/0 throws an exception of type int.
}      
Predicate Assertions

检查一个函数的返回值TRUE还是FALSE时,希望能够输出传入的参数是什么,以便失败后好跟踪

// 预测断言
bool MN(int m, int n)
{
   return m>n;
}
//检查一个函数的返回值TRUE还是FALSE时,希望能够输出传入的参数是什么,以便失败后好跟踪
TEST(PredicateAssertionTest, Demo)
{
   int m = 5, n = 6;
   EXPECT_PRED2(MN, m, n); //只提供<=5个参数 传递参数要与函数MN对应
}      

`EXPECT_PRED2(pred2, val1, val2);

ASSERT类似.PRED2可以到PRED5

最多支持5个参数.

浮点型检查

EXPECT_FLOAT_EQ(expected, actual)

EXPECT_DOUBLE_EQ(expected, actual)

ASSERT类似.

对相近的两个数比较:

EXPECT_NEAR(val1, val2, abs_error);

// 浮点型
TEST(FloatDoubleTest,Demo) {
   ASSERT_DOUBLE_EQ(1.1,1.1);
   EXPECT_FLOAT_EQ(1.2,4.0);
   EXPECT_NEAR(1.234,1.888,0.9);
//   EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2);
//   EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
   EXPECT_PRED_FORMAT2(testing::FloatLE,1,0);      // LE表示小于等于 也就是value1<=value2
   EXPECT_PRED_FORMAT2(testing::DoubleLE,0.1,0.2);
}      
// 类型检查
template <typename T>
class Tt{
public:
   void foo() {
       testing::StaticAssertTypeEq<bool, T>();     // 与下面调用一致就不报错,否则报错
  }
};
TEST(TypeAssertionTest, Demo)
{
   Tt<bool> tt;
   tt.foo();
}      
c++

继续阅读