如何使用gtest编写C++单元测试代码

目录

一.为什么要编写单元测试代码

相信很多人都不喜欢编写单元测试代码,但是单元测试对我们来说真的很重要,单元测试可以暴露出我们自己的代码的内部问题,从而保证我们自己的代码的正确性,避免出现各种bug。单元测试应该覆盖我们自己的代码的全部内部逻辑。

二.gtest是什么

gtest(全称googletest)是谷歌开源的一个单元测试框架,包含很多适用于具体场景的宏,可以方便的编写单元测试代码。

三.下载

源码下载地址:GitHub仓库

源码下载完成之后构建工程,基本构建方法:

cd googletest

mkdir build

cd build

cmake ...

可以根据需要调整构建指令,这样就可以构建出合适的工程出来,然后编译生成需要的库文件就可以了。

四.使用方法

本文讨论三种场景,给出示例代码,但是不展示效果,可以自行测试,这样理解效果更好。

示例使用的是VS2022。

如果编译时报错检测到"RuntimeLibrary"的不匹配项: 值"MTd_StaticDebug"不匹配值"MDd_DynamicDebug",原因是编译gtest库时设置的编译参数和编写单元测试代码时不一样。可以在项目属性->C/C+±>代码生成->运行库,改为一致即可。

4.1 场景一

如果需要测试的若干个case互不相关,可以使用TEST宏测试。

TEST宏的第一个参数是测试套件名,第二个参数是测试案例名,是自己填写的。一个测试套件包含若干个测试案例。

示例代码:

cpp 复制代码
//main.cpp

#include<gtest/gtest.h>

int Func(int data)
{
	return data;
}

TEST(TestDemo, test1)
{
	int data = 10;
	EXPECT_EQ(data, Func(10));
}

TEST(TestDemo, test2)
{
	int data = 5;
	EXPECT_EQ(data, Func(10));
}

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

	return RUN_ALL_TESTS();
}

4.2 场景二

如果需要测试的若干个case都具有相同的数据配置,可以使用TEST_F宏测试。

使用TEST_F宏需要先编写继承自testing::Test的固件类,用来提供数据配置。

TEST_F宏的第一个参数是测试套件名,必须要和固件类名一致,第二个参数是测试案例名,自己填写。一个测试套件包含若干个测试案例。

示例代码:

cpp 复制代码
//demo.h

#ifndef DEMO_H
#define DEMO_H

class Demo
{
public:
	explicit Demo(int data) :m_data(data) {}

	~Demo() noexcept = default;

	int GetData()
	{
		return m_data;
	}

private:
	int m_data;
};

#endif // !DEMO_H
cpp 复制代码
//test.h

#ifndef TEST_H
#define TEST_H

#include<iostream>

#include<gtest/gtest.h>

#include"demo.h"

class DemoTest : public testing::Test
{
protected:
	DemoTest() :m_demo(10) {}

	~DemoTest() noexcept override = default;

	void SetUp() override
	{
		//可以在这个函数里设置数据配置
		std::cout << "DemoTest::SetUp" << std::endl;
	}

	void TearDown() override
	{
		//可以在这个函数里释放资源
		std::cout << "DemoTest::TearDown" << std::endl;
	}

protected:
	Demo m_demo;
};

#endif // !TEST_H
cpp 复制代码
//test.cpp

#include"test.h"

TEST_F(DemoTest, test1)
{
	int data = 10;
	EXPECT_EQ(data, m_demo.GetData());
}

TEST_F(DemoTest, test2)
{
	int data = 5;
	EXPECT_EQ(data, m_demo.GetData());
}
cpp 复制代码
//main.cpp

#include<gtest/gtest.h>

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

	return RUN_ALL_TESTS();
}

4.3 场景三

如果同一个测试需要不同的输入参数,可以使用TEST_P宏测试。

使用TEST_P宏需要先编写继承自testing::TestWithParam<type>的固件类,<type>就是想要传入的参数的类型。

TEST_P宏的第一个参数是测试套件名,必须要和固件类名一致,第二个参数是测试案例名,自己填写。一个测试套件包含若干个测试案例。

示例代码:

cpp 复制代码
//test.h

#ifndef TEST_H
#define TEST_H

#include<iostream>

#include<gtest/gtest.h>

class DemoTest : public testing::TestWithParam<int>
{
protected:
	DemoTest() = default;

	~DemoTest() noexcept override = default;

	void SetUp() override
	{
		//可以在这个函数里设置数据配置
		std::cout << "DemoTest::SetUp" << std::endl;
	}

	void TearDown() override
	{
		//可以在这个函数里释放资源
		std::cout << "DemoTest::TearDown" << std::endl;
	}
};

#endif // !TEST_H
cpp 复制代码
//test.cpp

#include"test.h"

TEST_P(DemoTest, test1)
{
	int data = 5;
	EXPECT_EQ(data, GetParam());
}

TEST_P(DemoTest, test2)
{
	int data = 10;
	EXPECT_EQ(data, GetParam());
}

INSTANTIATE_TEST_SUITE_P(DEMO, DemoTest, testing::Values(0, 5, 10));
cpp 复制代码
//main.cpp

#include<gtest/gtest.h>

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

	return RUN_ALL_TESTS();
}

五.其他

  1. Linux下使用方法类似。

  2. 可以在官方文档查看更多用法。

  3. 可以使用gmock进行打桩。

相关推荐
haofafa3 分钟前
STL之动态数组
开发语言·c++
无敌最俊朗@1 小时前
梳理了音视频开发核心知识点
c++·音视频
专注VB编程开发20年1 小时前
.NET Reflector反编绎,如何移除DLL中的一个公开属性
开发语言·c++·c#
落羽的落羽1 小时前
【Linux系统】C/C++的调试器gdb/cgdb,从入门到精通
linux·服务器·c语言·c++·人工智能·学习·机器学习
在下雨5991 小时前
条件变量与互斥锁复习
c++·面试
dvlinker2 小时前
使用Visual Studio中的数据断点快速定位内存越界问题的实战案例分享
c++·visual studio·memset·内存越界·栈内存越界·堆内存越界·数据断点
9ilk2 小时前
【基于one-loop-per-thread的高并发服务器】--- 项目介绍&&模块划分
运维·服务器·c++·后端·中间件
@木辛梓2 小时前
Linux 线程
linux·开发语言·c++
无语子yyds3 小时前
C++双指针算法例题
数据结构·c++·算法
羑悻的小杀马特3 小时前
ProtoBuf语法揭秘:探秘编译魔法与性能优化策略,解锁多层级选项配置的底层奥秘
c++·编程·protobuf