googletest
1.ubuntu18.04 安装googletest并测试
①安装
sudo apt-get install libgtest-dev cmake
cd /usr/src/gtest
sudo cmake CMakeLists.txt
sudo make //默认安装在/usr/src目录下
②测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XfUr5ZCl-1681285700017)(E:\Typora\img\image-20230412142503589.png)]
建立测试文件夹
mkdir ./test_unit/
cd ./test_unit/
mkdir ./include
mkdir ./lib --------存放.a文件
sudo cp -rf /usr/src/gtest/include/gtest ./include
sudo cp /usr/lib/*.a ./lib -----拷贝文件
测试文件 gtest.cpp
#include<gtest/gtest.h>
// Returns true iff n is a prime number.
bool IsPrime(int n)
{
// Trivial case 1: small numbers
if (n <= 1) return false;
// Trivial case 2: even numbers
if (n % 2 == 0) return n == 2;
// Now, we have that n is odd and n >= 3.
// Try to divide n by every odd number i, starting from 3
for (int i = 3; ; i += 2) {
// We only have to try i up to the squre root of n
if (i > n/i) break;
// Now, we have i <= n/i < n.
// If n is divisible by i, n is not prime.
if (n % i == 0) return false;
}
// n has no integer factor in the range (1, n), and thus is prime.
return true;
}
class IsPrimeParamTest : public::testing::TestWithParam<int>
{
};
TEST_P(IsPrimeParamTest, HandleTrueReturn)
{
int n = GetParam();
EXPECT_TRUE(IsPrime(n));
}
INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 16 ,19 ,21 , 23, 17));
手动链接gtest的头文件和静态库进行编译执行
g++ gtest.cpp -I ./include/gtest -L ./lib -lgtest_main -lgtest -lpthread -o gtest
测试结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQgScJDD-1681285700018)(E:\Typora\img\image-20230412143140581.png)]
③好的测试框架应满足的条件:
- 独立、可重复
- 反应测试代码结构
- 测试失效时要尽可能地提供更多的错误信息
- 一个测试能发现/修复多个错误,只关注测试本身/自动跟踪测试 不需要枚举
- 测试简洁高效
2.单元测试 事件机制 内存泄漏机制
googletest:单元测试+测试案例
googlemock:打桩测试
①单元测试(一个项目对应一个单元测试)
一个单元测试包含多个测试套件,一个测试套件包含多个测试案例,一个测试案例包含多个断言
int Factorial(int n);
int IsPrimer(int n);
#define TEST_T(test_suite_name,test_name);
TEST_T(Factorial,Negative){
EXPECT_EQ(1,Factorial(-5));
EXPECT_GT(Factorial(-5),0);
}
断言语句
EXPECT_FALSE() << ".....";
EXPECT_TRUE();
EXPECT_EQ();
ASSERT_TRUE(); ASSERT_FALSE(); 、
ASSERT_TRUE(Abs(1) == 1) << "Abs(1)=1";//这样在判断不通过时会有后面打印"Abs(1)=1"。
错误分为致命错误(assert)和非致命错误(expect)
1、ASSERT_系列:如果当前点检测失败则退出当前函数
2、EXPECT_系列:如果当前点检测失败则继续往下执行
②测试夹具
简单测试:函数测试 类测试 (测试套件名 测试案例名)
测试夹具:继承一个类 (不同测试案例之间可以共享数据)
#define TEST_F(test_fixture,test_name) 【测试夹具名 测试案例名】
全局的事件机制(针对整个测试程序)
实现全局的事件机制,需要创建一个自己的类,然后继承testing::Environment类,然后分别实现成员函数SetUp()和TearDown(),同时在main函数内进行调用,即"testing::AddGlobalTestEnvironment(new MyEnvironment);",通过调用函数我们可以添加多个全局的事件机制。
SetUp()函数是在所有测试开始前执行。
TearDown()函数是在所有测试结束后执行。
代码示例
#include <iostream>
#include <gtest/gtest.h>
using namespace std;
class MyEnvironment0 : public testing::Environment
{
public:
virtual void SetUp()
{
cout << "Global event0 : start" << endl;
}
virtual void TearDown()
{
cout << "Global event0 : end" << endl;
}
};
class MyEnvironment1 : public testing::Environment
{
public:
virtual void SetUp()
{
cout << "Global event1 : start" << endl;
}
virtual void TearDown()
{
cout << "Global event1 : end" << endl;
}
};
TEST(GlobalTest0, test0)
{
EXPECT_EQ(1, 1);
};
TEST(GlobalTest0, test1)
{
EXPECT_EQ(2, 2);
};
TEST(GlobalTest1, test0)
{
EXPECT_EQ(3, 3);
};
int main(int argc, char *argv[])
{
testing::AddGlobalTestEnvironment(new MyEnvironment0);
testing::AddGlobalTestEnvironment(new MyEnvironment1);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
局部事件机制
测试套件的事件机制我们同样需要去创建一个类,继承testing::Test,实现两个静态(static)函数SetUpTestCase()和TearDownTestCase(),测试套件的事件机制不需要像全局事件机制一样在main注册,而是需要将我们平时使用的TEST宏改为TEST_F宏。
SetUpTestCase()函数是在测试套件第一个测试用例开始前执行。
TearDownTestCase()函数是在测试套件最后一个测试用例结束后执行。
同一个测试套件(类名),不同测试案例之间共享数据
SetUpTestCase()可以对共享的数据进行一定的初始化
注:TEST_F的第一个参数使我们创建的类名,也就是当前测试套件的名称。
多个测试场景需要相同数据配置的情况,用TEST_F
测试代码
#include "gtest/gtest.h"
#include <iostream>
using namespace std;
/*
TestSuite事件
需要写一个类,继承testing::Test,然后实现两个**静态**方法:
SetUpTestCase方法在第一个TestCase之前执行;TearDownTestCase方法在最后一个TestCase之后执行。
*/
class single :public testing::Test
{
public:
/* **必须要加static 否则TEST_P会报错** */
static void SetUpTestCase()
{
std::cout << "局部事件机制,针对TestSuite事件 single start" << std::endl;
}
static void TearDownTestCase()
{
std::cout << "局部事件机制,针对TestSuite事件 single end" << std::endl;
}
};
int add_number(int a, int b) {
return (a + b);
}
int reduce_number(int a, int b) {
return (a - b);
}
TEST_F(single,add_num) { //此时使用的是TEST_F宏,test case名称都为类名:jj
EXPECT_EQ(3, add_number(1, 2));
std::cout << "add_num ASSERT SUCCEED!" << std::endl;
}
TEST_F(single, reduce_num) {
EXPECT_EQ(2, reduce_number(3, 1));
std::cout << "reduce_num ASSERT SUCCEED!" << std::endl;
}
执行代码
g++ single.cpp -I ./include/gtest -L ./lib -lgtest_main -lgtest -lpthread -o gtestsingle
执行结果
个体事件机制
测试用例的事件机制的创建和测试套件的基本一样,不同地方在于测试用例实现的两个函数分别是SetUp()和TearDown(),这两个函数不是静态函数。
SetUp()函数是在一个测试用例的开始前执行。TearDown()函数是在一个测试用例的结束后执行。
测试代码
#include "gtest/gtest.h"
#include <iostream>
using namespace std;
class TestMap :public testing::Test
{
public:
//加了Virtual关键字的函数就是虚拟函数,在基类的派生类中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。
virtual void SetUp() //TEST跑之前会执行SetUp
{
cout << "我是每个方法之前都会执行的SetUp" << endl;
test_map.insert(make_pair(1, 0));
test_map.insert(make_pair(2, 1));
test_map.insert(make_pair(3, 2));
test_map.insert(make_pair(4, 3));
test_map.insert(make_pair(5, 4));
}
virtual void TearDown() //TEST跑完之后会执行TearDown
{
cout << "我是每个方法之后都会执行的TearDown" << endl;
test_map.clear();
}
map<int, int> test_map;
};
TEST_F(TestMap, Find) //此时使用的是TEST_F宏
{
map<int, int>::iterator it = test_map.find(1);
ASSERT_NE(it, test_map.end());
cout << "find函数断言成功" << endl;
}
TEST_F(TestMap, Size)
{
ASSERT_EQ(test_map.size(), 5)<<"字典大小等于5";
cout << "Size函数断言成功" << endl;
}
注意:
- 在同一份TestCase中不能同时出现TEST和TEST_F两者进行混用;
- 局部事件机制、个体事件机制 继承类testing::Test,使用TEST_F宏
- 全局事件机制继承继承类testing::Environment**,同时在main函数内进行调用,即添加以下代码:testing::AddGlobalTestEnvironment(new MyEnvironment); 和使用哪种宏无关
③内存泄漏机制
内存泄露原因:C++ new出了对象但是没有delete
operator new过程:首先malloc一定的内存,在分配内存的基础上调用构造函数对分配的内存进行初始化
内存泄露解决方法:复写operator new/delete
中不能同时出现TEST和TEST_F两者进行混用;
2. 局部事件机制、个体事件机制 继承类testing::Test,使用TEST_F宏
3. 全局事件机制继承继承类testing::Environment**,同时在main函数内进行调用,即添加以下代码:testing::AddGlobalTestEnvironment(new MyEnvironment); 和使用哪种宏无关
③内存泄漏机制
内存泄露原因:C++ new出了对象但是没有delete
operator new过程:首先malloc一定的内存,在分配内存的基础上调用构造函数对分配的内存进行初始化
内存泄露解决方法:复写operator new/delete