gTest
目录
在Clion上安装
下载后解压到项目
配置cmake
cmake_minimum_required(VERSION 3.16)
project(myTest)
message("------------ Options -------------")
message(" CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(" CMAKE_BUILD_TYPE: Hello World!")
# 编译google test,会在当前目录生成libtest.a静态库
add_subdirectory(./googletest)
#头文件
include_directories(${PROJECT_SOURCE_DIR}/src/include ./googletest/include)
#源文件
aux_source_directory(${PROJECT_SOURCE_DIR}/src/main dir_srcs)
#库文件 : libtest.a 添加到链接路径中
link_directories(${PROJECT_SOURCE_DIR}/lib ${PROJECT_SOURCE_DIR}/googletest)
#需要添加googletest运行需要的pthread
set(LIBRARIES pthread)
set(CMAKE_CXX_STANDARD 11)
add_executable(myTest main.cpp)
target_link_libraries(${PROJECT_NAME} gtest)
测试点
TEST(TestSuiteName,TestCaseName)
最简单的
#include <iostream>
#include <gtest/gtest.h>
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
在main的上面空行(不一定空行,其实只要不在方法里都行),点Run all运行全部
就会产生底下这个
如果运行main的话
断言
ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。
EXPECT_* 系列的断言,当检查点失败时,继续往下执行。
可以通过ASSERT_*<<“msg”; 输出msg
判断bool
ASSERT_* | EXPECT_* | 功能 |
ASSERT_TRUE(condition) | EXPECT_TRUE(condition) | condition是否为true |
ASSERT_FALSE(condition) | EXPECT_FALSE(condition) | condition是否为false |
数值判断
ASSERT_* | EXPECT_* | 功能 |
ASSERT_EQ(expect,actual) | EXPECT_EQ(expect,actual) | expect==actual |
ASSERT_NE(expect,actual) | EXPECT_NE(expect,actual) | expect!=actual |
ASSERT_LT(expect,actual) | EXPECT_LT(expect,actual) | expect<actual |
ASSERT_LE(expect,actual) | EXPECT_LE(expect,actual) | expect<=actual |
ASSERT_GT(expect,actual) | EXPECT_GT(expect,actual) | expect>actual |
ASSERT_GE(expect,actual) | EXPECT_GE(expect,actual) | expect>=actual |
字符串判断
ASSERT_* | EXPECT_* | 功能 |
ASSERT_STREQ(expect,actual) | EXPECT_STREQ(expect,actual) | 字符级别相等 |
ASSERT_STRNE(expect,actual) | EXPECT_STRNE(expect,actual) | 字符级别不等 |
ASSERT_STRCASEEQ(expect,actual) | EXPECT_STRCASEEQ(expect,actual) | 忽略大小写后,字符级别相等 |
ASSERT_STRCASENE(expect,actual) | EXPECT_STRCASENE(expect,actual) | 忽略大小写后,字符级别不等 |
显示返回成功或失败
显示返回成功SUCCEED()
ASSERT版本: FAIL()
EXPECT版本: ADD_FAILURE()
异常检查
ASSERT_* | EXPECT_* | 功能 |
ASSERT_THROW(statement,expection_type) | EXPECT_THROW(statement,expection_type) | statement抛出的异常类型为expection_type |
ASSERT_ANY_THROW(statement) | EXPECT_ANY_THROW(statement) | statement抛出的任意类型异常 |
ASSERT_NO_THROW(statement) | EXPECT_NO_THROW(statement) | statement不抛异常 |
输出更详细信息
ASSERT_* | EXPECT_* | 功能 |
ASSERT_PRED1(pred,val1) | EXPECT_PRED1(pred,val1) | pred(val1)是否输出true |
ASSERT_PRED2(pred,val1,val2) | EXPECT_PRED2(pred,val1,val2) | pred(val1,val2)是否输出true |
以此类推,到ASSERT_PRED5
自定义输出
ASSERT_* | EXPECT_* | 功能 |
ASSERT_PRED_FORMAT1(pred,val1) | EXPECT_PRED_FORMAT1(pred,val1) | pred(val1)是否输出true |
ASSERT_PRED_FORMAT2(pred,val1,val2) | EXPECT_PRED_FORMAT2(pred,val1,val2) | pred(val1,val2)是否输出true |
以此类推,到ASSERT_PRED_FORMAT5
浮点数相等
ASSERT_* | EXPECT_* | 功能 |
ASSERT_FLOAT_EQ(expect,actual) | EXPECT_FLOAT_EQ(expect,actual) | expect==actual |
ASSERT_DOUBLE_EQ(expect,actual) | EXPECT_NE(expect,actual) | expect!=actual |
相近判断
ASSERT_NEAR(
val1, val2, abs_error
) :|val1-val2|<=abs_error
#include <iostream>
#include <gtest/gtest.h>
#include <string>
int add(const int& a,const int& b){return a+b;}
TEST(TEST_SUCCESS,TEST1){
EXPECT_EQ(3,add(1,2)); //判断相等
}
TEST(TEST_FAILED,TEST1){
EXPECT_EQ(4,add(1,2));
}
int x[]={1,2,3,4};
int y[]={1,3,2,4};
TEST(TEST_ARRAY,TEST1){
for(int i=0;i<4;++i){
EXPECT_EQ(x[i],y[i]);
}
}
TEST(TEST_ARRAY,TEST2){
for(int i=0;i<4;++i){
EXPECT_EQ(x[i],y[i])<< "Vectors x and y differ at index " << i;
}
}
TEST(string_cmp_test,test1){
const char* pszCoderZh="CoderZh";
const 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());
}
TEST(string_cmp_test,test2){
std::string str="敲你马";
// std::wstring wstr=L"敲你马"; //不知道为什么崩了
EXPECT_STREQ("敲你马",str.c_str());
// EXPECT_STREQ(L"敲你马",wstr.c_str());
}
TEST(explicit_test,test1){
ADD_FAILURE()<<"failed";//返回失败
// FAIL();
SUCCEED();//直接返回成功
}
int gcd(int a,int b){
if(a==0||b==0)throw "don't do that";
int c=a%b;
while(c){
a=b;
b=c;
c=a%b;
}
return b;
}
TEST(foo_test,handle_zero_input){
EXPECT_ANY_THROW(gcd(0,5)); //期待抛出任何异常
EXPECT_THROW(gcd(5,0),const char*); //抛出指定类型异常
}
bool mutuallyPrime(const int& a,const int& b){
return gcd(a,b)==1;
}
TEST(predicate_assert_test,test1){
EXPECT_PRED2(mutuallyPrime,5,10); //期待mutuallyPrime(5,4)返回true
}
testing::AssertionResult AssertFoo(const char* m_expr, const char* n_expr, const char* k_expr, int m, int n, int k) {
const int result=gcd(m,n);
if (result == k)
return testing::AssertionSuccess();
testing::Message msg;
msg << m_expr << "?和?" << n_expr << "?的最大公约数应该是:" << result << "?而不是:" << k_expr;
return testing::AssertionFailure(msg);
}
TEST(AssertFooTest, HandleFail){
EXPECT_PRED_FORMAT3(AssertFoo, 3, 6, 2); //自定义错误输出
}
TEST(FloatTest,Test1){
EXPECT_FLOAT_EQ(1.6f,5.0f/2);
}
TEST(FloatTest,Test2){
EXPECT_DOUBLE_EQ(1.6,5.0/2);
}
TEST(FloatTest,Test3){
EXPECT_PRED_FORMAT2(testing::FloatLE, 1.6f,5.0f/2);
EXPECT_PRED_FORMAT2(testing::DoubleLE, 1.6,5.0/2);
}
TEST(NearTest,Test1){
EXPECT_NEAR(1,2,1);
}
//template <typename T>
//class FooType {
//public:
// void Bar() {
// testing::StaticAssertTypeEq<int, T>();
// }
//};
//
//TEST(TypeAssertionTest,Demo)
//{
// FooType<bool>fooType;
// fooType.Bar();
//}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
事件
全局事件
SetUp()方法在所有案例执行前执行
TearDown()方法在所有案例执行后执行
需要继承testing::Environment,并在main中使用testing::AddGlobalTestEnvironment(你的类);
进行注册
如果有多个,你可以注册多个
TestSuite事件
我们需要写一个类,继承
testing::Test,然后实现两个静态方法
SetUpTestCase:每个TestSuite执行前执行
TearDownTestCase:每个TestSuite执行后执行
测试点不再使用TEST,而是TEST_F,第一个参数传你的类,第二个传test case名字
TestCase事件
我们需要写一个类,继承testing::Test,然后实现两个静态方法
SetUp:每个TestCase执行前执行
TearDown:每个TestCase执行后执行
测试点不再使用TEST,而是TEST_F,第一个参数传你的类,第二个传test case名字
#include <iostream>
#include <gtest/gtest.h>
#include <string>
//要有test case才会执行setup和tear down
class FooEnvironment:public testing::Environment{
public:
void SetUp() override{ //在所有案例执行前执行
std::cout<<"Foo FooEnvironment setUp"<<std::endl;
}
void TearDown() override{ //方法在所有案例执行后执行
std::cout<<"Foo FooEnvironment tearDown"<<std::endl;
}
};
class FooTest:public testing::Test{
protected:
static void SetUpTestCase(){ //第一个TestCase之前执行
a=new int[10];
for(int i=0;i<10;++i)a[i]=i;
std::cout<<"init"<<std::endl;
}
static void TearDownTestCase(){ //在最后一个TestCase之后执行
delete[] a;
a= nullptr;
std::cout<<"destroy"<<std::endl;
}
static int* a;
};
int* FooTest::a= nullptr;
//使用TEST_F这个宏,第一个参数必须是我们上面类的名字
TEST_F(FooTest,test1){
for(int i=0;i<10;++i){
EXPECT_EQ(i,a[i]);
}
}
TEST_F(FooTest,test2){
for(int i=0;i<10;++i){
EXPECT_EQ(i-1,a[i]);
}
}
class FooTest2:public testing::Test{
public:
void SetUp() override { //在每个TestCase之前执行
std::cout<<"start case"<<std::endl;
}
void TearDown() override { //在每个TestCase之后执行
std::cout<<"end case"<<std::endl;
}
};
//使用TEST_F这个宏,第一个参数必须是我们上面类的名字
TEST_F(FooTest2,test1){
SUCCEED();
}
int main(int argc, char **argv)
{
testing::AddGlobalTestEnvironment(new FooEnvironment);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
参数化
写一个类,继承
testing::TestWithParam<T>,这个T就是测试的类型
有个类型参数化没怎么看懂,以后再说
INSTANTIATE_TEST_SUITE_P(prefix,test_suite_name,…)
第一个参数是前缀,
第二个参数是名称,就是你的类名
第三个是参数生成器
参数生成器 | 功能 |
Values(a,b,…) | 依次取a,b,… |
ValuesIn(container) | 依次取容器中的值 |
ValuesIn(begin, end) | 依次取begin在end中的值 |
Bool() | 生成false,true |
Range(start,end,step) | 类似py的range |
Combine(g1,g2,…) | 组合生成器g1,g2,…,返回tuple<类型1,类型2,…>,需要#includ<tuple> |
如果需要事件(如teardown)可以直接在类中写,不用继承testing::test以及使用TEST_F
类型参数化,没怎么看懂,以后再说
#include <iostream>
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <tuple>
bool isPrime1(int x){
if(x<2)return false;
if(x==2||x==3)return true;
if(x%6!=1&&x%6!=5)return false;
for(int i=5;i*i<=x;i+=6){
if(x%i==0||x%(i+2)==0)return false;
}
return true;
}
bool isPrime2(int x){
if(x<2)return false;
for(int i=2;i*i<=x;++i){
if(x%i==0)return false;
}
return true;
}
class IsPrimeParamTest:public testing::TestWithParam<int>{
};
//INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));
//第一个参数是测试案例的前缀,可以任意取,但是当第二个参数相同时,第一个参数必须不同
//第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同,如:IsPrimeParamTest
//第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:
//Values(a,b,c,...)依次取a,b,c...
INSTANTIATE_TEST_SUITE_P(TrueReturn1, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));
//Range,类似py的range
INSTANTIATE_TEST_SUITE_P(TrueReturn2,IsPrimeParamTest,testing::Range(1,10001,1));
int a[]{3,5,11,23,17};
//ValuesIn,容器
INSTANTIATE_TEST_SUITE_P(TrueReturn3,IsPrimeParamTest,testing::ValuesIn(a));
//ValuesIn,迭代器
std::vector<int> v{1,2,4,5,6};
INSTANTIATE_TEST_SUITE_P(TrueReturn4,IsPrimeParamTest,testing::ValuesIn(v.begin(),v.end()));
TEST_P(IsPrimeParamTest,test1){
int n=GetParam();
ASSERT_EQ(isPrime2(n),isPrime1(n));
}
class BoolTest:public testing::TestWithParam<bool>{
};
//Bool,返回true,false
INSTANTIATE_TEST_SUITE_P(TrueReturn1,BoolTest,testing::Bool());
TEST_P(BoolTest,test1){
bool n=GetParam();
ASSERT_EQ(true,n);
}
class CombineTest:public testing::TestWithParam<std::tuple<int,int,int> >{
};
//Combine,进行排列组合,里面每个参数都是一个参数生成器(也许能套娃,但是我懒得试了),GetParam会返回tuple
//需要#include<tuple>
INSTANTIATE_TEST_SUITE_P(
TrueReturn1,
CombineTest,
testing::Combine(
testing::ValuesIn(a),
testing::ValuesIn(v),
testing::Range(1,5)));
TEST_P(CombineTest,test1){
std::tuple<int,int,int> p=GetParam();
//用std::get<0>获取第0个参数
EXPECT_NE(std::get<0>(p)+std::get<1>(p),std::get<2>(p)+std::get<1>(p));
}
//还有个类型参数化,没怎么看懂,以后再说
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
运行参数
–gtest_list_tests | 使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表 |
–gtest_filter |
对执行的测试案例进行过滤,支持通配符 ? 单个字符 * 任意字符 – 排除,如,-a 表示除了a : 取或,如,a:b 表示a或b |
–gtest_repeat=[COUNT] |
-1 无限次 |
–gtest_color=(yes|no|auto) | 输出命令行时是否使用一些五颜六色的颜色。默认是auto,这个好像在clion的控制台没有什么卵用 |
–gtest_print_time | 输出命令行时是否打印每个测试案例的执行时间。默认是不打印的。但是好像clion中,是默认打印的 |
–gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH] |
将测试结果输出到一个xml中 不指定输出路径时,默认为案例当前路径。 |
–gtest_break_on_failure | 当案例失败时停止 |
其他的再说吧
有两种方法,一种是在main中,用testing::GTEST_FLAG(),
如gtest_list_tests,把gtest这个前缀去掉,放括号里
int main(int argc, char **argv)
{
//--gtest_list_tests
testing::GTEST_FLAG(list_tests) = "";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
另一种是直接在clion中指定
参考
https://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html