gtest 总结

gtest without main

Google的C测试框架有两个输出库:一个是gtest.lib,另一个是gtest_main.lib。

依赖gtest.lib 需要实现自己的入口函数main

int main(int argc, char* argv[])
{
	testing::AddGlobalTestEnvironment(new FooEnvironment);
	::testing::InitGoogleTest(&argc, argv); 

	return RUN_ALL_TESTS();  

	return 0;

}

依赖gtest_main.lib 提供了测试应用程序入口点(即主要功能)的默认实现,添加编译依赖-l gtest_main

[Getting started with Google C++ Testing Framework](javascript:void())引用:

“[…] maybe you think that writing
all those main() functions is too much
work? We agree with you completely and
that’s why Google Test provides a
basic implementation of main(). If it
fits your needs, then just link your
test with gtest_main library and you

Gmock

C++ mock一个新类继承抽象类

使用MOCK_METHODx宏声明的类成员函数;详见 MOCK_METHOD*系列宏,参考如下博客


使用EXPECT_CALL等一系列宏来指定这些函数在被调用时的动作。

在此基础上期望待测函数的输出

C mock 三种方式

方法一:利用C语言的预处理(在编译之前进行Mock)
#ifdef TESTING

#define depend_func(account_no,item)\ 

	function body\

/* extend as function body during compile procedure, while the function name. so will not find the depend_func symble in ld process */

#endif
方法二: 使用函数指针(编译期进行mock)
#ifdef TESTING
  depend_func= depend_func_mock
#else
  depend_func= depend_func_real
#endif
方法三: 在编译之后 Link时候进行替换

编写包括depend_func的库函数,在link的时候使用这个假的库函数

linux_gtest

linux下gtest的使用

环境配置(ubuntu 14.04 32bit)

$ ./travis.sh

$ cmake ./CMakeLists.txt

$ make $ sudo make install

### makefile

.PHONY: all clean

CC=g++
OBJ_DIR=./obj
HEADERS=-I.
DEBUG=-g -ggdb
WALL=-Wall -W
CFLAGS=$(WALL) $(DEBUG)
L_CC=$(CC) $(CFLAGS) $(HEADERS)

C_SRC=${wildcard *.cpp}
C_OBJ=$(patsubst %.cpp, $(OBJ_DIR)/%.o, $(C_SRC)) #目标文件
C_EXE=a.out

all:prepare $(C_EXE)

prepare:
	@if [ ! -d $(OBJ_DIR)  ];then mkdir $(OBJ_DIR); fi

$(C_EXE):$(C_OBJ)
	$(L_CC) $^ -o $@ -lgtest -lgtest_main -lpthread

$(OBJ_DIR)/%.o:%.cpp
	$(L_CC) -c $< -o $@

clean:
	@-rm -f $(C_EXE)
	@-rm -rf $(OBJ_DIR)

参数化

在测试时,经常需要考虑被测函数传入不同参数的值的情况。当然可以写很多的Assert或 EXPECT断言,但是是不是太多了,要写多少重复的的东西

比如

TEST(IsPrimeTest, HandleTrueReturn)
{
    EXPECT_TRUE(IsPrime(3));
    EXPECT_TRUE(IsPrime(5));
    EXPECT_TRUE(IsPrime(11));
    EXPECT_TRUE(IsPrime(23));
    EXPECT_TRUE(IsPrime(17));
}

参数化,采用一个较为通用的方法,你要测多少数据,自己加上就行了,不需要copy那么多一样的代码

class TestSqare:public testing::TestWithParam<int>{
protected:
    int Sqare(int a) {
        return a*a;
    }
    int a;
};

TEST_P(TestSqare,case1){
    a = GetParam();
    EXPECT_EQ(a*a,Sqare(a));
}

INSTANTIATE_TEST_CASE_P(Sare,TestSqare,testing::Values(1,2,3,4));

int main(int argc,char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

参考:

事件机制

gtest提供事件机制,主要是测试时候,可以在测试案例前后做一些操作

全局事件

要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。

  1. SetUp()方法在所有案例执行前执行
  2. TearDown()方法在所有案例执行后执行
// 全局事件
class FooEnvironment : public testing::Environment
{
public:

	// 1. SetUp()方法在所有案例执行前执行
	virtual void SetUp();

	// 2. TearDown()方法在所有案例执行后执行
	virtual void TearDown();

};

void FooEnvironment::SetUp()
{
	std::cout << "Foo FooEnvironment SetUP" << std::endl;
}


void FooEnvironment::TearDown()
{
	std::cout << "Foo FooEnvironment TearDown" << std::endl;
}


int main(int argc, char* argv[])
{
	testing::AddGlobalTestEnvironment(new FooEnvironment);
	::testing::InitGoogleTest(&argc, argv);  
	return RUN_ALL_TESTS();  

	//return 0;
}

死亡测试

“死亡”指的是程序的崩溃。通常在测试过程中,需要考虑到各种各样的输入,有的输入可能导致程序崩溃;或者某段程序本身存在内存泄漏,指针错误访问等崩溃现象,这时我们需要检查程序是否按照预期的方式挂掉,这也就是所谓的“死亡测试”。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。

具体会使用如下的两个宏

  1. ASSERT_DEATH(statement, regex`);
  2. EXPECT_DEATH(statement, regex`);
#include "gtest/gtest.h"

int Add(int a,int b)
{
	return a + b;
}

void FooDeath()
{
	int *pInt = NULL;
	*pInt = 2;
}

void FooDeath2()
{
}

// 正常测试
TEST(fun, Add)  
{  
	EXPECT_EQ(1, Add(1,8)); 
	EXPECT_EQ(10, Add(2,8)); 
	EXPECT_EQ(40, Add(24,16)); 
}

// gtest会优先运行死亡测试案例
TEST(FooDeathTest, Demo)
{
	EXPECT_DEATH(FooDeath(), "");
}

// 死亡测试,当函数本身是正确的
TEST(Foo2DeathTest, Demo2)
{
	EXPECT_DEATH(FooDeath2(), "");
}

int main(int argc, char* argv[])
{
	::testing::InitGoogleTest(&argc, argv);  
	
	return RUN_ALL_TESTS();

	//return 0;
}
  • 死亡测试时优先于正常的测试案例的,跟程序放的上下文位置没有关系,死亡测试请使用*DeathTest的测试名
  • 死亡测试,如果真的是"死亡"的,那么会出现绿色的正常的RUN
  • 死亡测试,如果不是真的“死亡”,会出现红色的“failed to die”
//*_EXIT(statement, predicate, regex`) 
void func(int c)
{
	if(c <= 0)
		_exit(1);
	else 
		_exit(2);
}

TEST(ExitDeathTest, Demo)
{
	EXPECT_EXIT(func(-1), testing::ExitedWithCode(1),"");
}

TEST(Exit2DeathTest, Demo2)
{
	EXPECT_EXIT(func(1), testing::ExitedWithCode(1),"");
}

int main(int argc, char* argv[])
{
	::testing::InitGoogleTest(&argc, argv);  
	
	return RUN_ALL_TESTS();

	//return 0;
}

运行参数

使用gtest编写的测试案例通常本身就是一个可执行文件,因此运行起来非常方便。同时,gtest也为我们提供了一系列的运行参数(环境变量、命令行参数或代码里指定),使得我们可以对案例的执行进行一些有效的控制。

gtest三种运行参数

  1. 系统环境变量
  2. 命令行参数
  3. 代码中指定FLAG

面能将特殊结果放入到一个xml文档中

int main(int argc, char* argv[])
{
	testing::GTEST_FLAG(output) = "xml:";

	::testing::InitGoogleTest(&argc, argv);  
	
	return RUN_ALL_TESTS();
}

命令行参数

–gtest_list_tests

–gtest_list_tests 使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。

–gtest_filter 对执行的测试案例进行过滤,支持通配符

–gtest_filter=Exit*

运行所有测试案例名称为Exit开头的


通过命令行参数还能设置测试案例的输出

  • 设置输出的一些颜色
  • 打印出测试案例的执行时间(默认不打印)
  • 将测试结果输出到另外的文件中(上文有实例)

通过命令行还能对案例异常进行处理

  • 设置当案例失败时,如抛出异常,弹出对话框
  • 调试模式下,案例失败时停止,方面调试

通过文件配置用例执行/* undo*/

自定义测试类

class MyTestClass : public ::testing::Test
{
public:
	MyTestClass() {}
	virtual ~MyTestClass() {}

	virtual void SetUp() {
		pCal = std::auto_ptr<Cal>(new Cal());
	}
	virtual void TearDown() {
	}
public:
	std::auto_ptr<Cal> pCal;
};

// 第一个参数必须是类名MyTestClass
TEST_F(MyTestClass, test_add)
{
	pCal->setA(2);
	pCal->setB(3);
	EXPECT_TRUE(pCal->add() == 5);
}

TEST_F(MyTestClass, test_sub)
{
	pCal->setA(2);
	pCal->setB(3);
	EXPECT_TRUE(pCal->sub() == -1);
}