基本了解
google提供的一个C++测试框架,主要就是简化测试单元的书写,具有高效、灵活可拓展的特点
主要特点
- 简单易用:gtest 提供了清晰且易于使用的 API,便于开发者快速编写单元测试。
- 丰富的断言支持:gtest 提供了多种断言(assertion)来验证不同类型的条件(如
EXPECT_EQ
、ASSERT_TRUE
等),使得测试结果的验证更为精确。 - 支持测试夹具 (Test Fixtures):允许在多个测试间共享测试环境和资源,避免重复代码。
- 自动化测试结果报告:gtest 会自动生成测试的执行结果,报告哪些测试通过,哪些失败。
- 兼容性:gtest 能够与多种构建系统(如 CMake)集成,并且可以与持续集成工具一起使用。
- 跨平台支持:支持 Windows、Linux、Mac 等操作系统,能够运行在各种开发环境下。
- 扩展性:你可以根据需要扩展 gtest 提供的功能,比如自定义断言或添加新的测试功能。
基本概念
- 测试案例 (Test Case): 测试案例是一个包含一个或多个测试的类。每个测试类继承自
::testing::Test
,并包含测试代码和测试夹具(如果需要的话) - 测试夹具 (Test Fixture): 测试夹具是指在多个测试中需要共享的环境或状态,通常用于在测试开始之前进行一些初始化工作,测试结束后进行清理。通过继承
::testing::Test
类来创建 - 测试套件 (Test Suite): 测试套件由多个测试案例(Test Case)组成,它们共享相同的测试环境。每个测试案例是一个测试类,包含一个或多个测试方法
- 断言 (Assertions)(重点): 断言用于验证程序的行为是否符合预期,gtest 提供了多种断言
EXPECT_EQ(val1, val2)
:期望val1
和val2
相等(不等时记录失败,但继续执行)。ASSERT_EQ(val1, val2)
:期望val1
和val2
相等(不等时会终止当前测试)。EXPECT_TRUE(condition)
:期望条件为真。EXPECT_FALSE(condition)
:期望条件为假。ASSERT_TRUE(condition)
:期望条件为真,并终止当前测试(如果不为真)。ASSERT_FALSE(condition)
:期望条件为假,并终止当前测试(如果不为假)。
- 测试运行器 (Test Runner): gtest 使用一个测试运行器来执行所有的测试并报告结果,通常我们通过命令行运行测试可执行文件来启动测试运行
初步上手使用
测试简单加法运算
#include<iostream>
#include<gtest/gtest.h>
int add(int x , int y)
{
return x+y;
}
TEST(函数测试,加法函数测试1)
{
//判断最终结果是否为40
ASSERT_EQ(add(20,20),40);
ASSERT_LT(add(10,10),30);
}
TEST(函数测试, 字符串测试)
{
std::string str = "hello gtest";
ASSERT_EQ(str, std::string("hello gtest")); // 类型一致
ASSERT_EQ(str, std::string("hello world")); // 比较失败
}
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc,argv);
//运行所有测试用例
return RUN_ALL_TESTS();
}
EXPECT_EQ(val1, val2)
和ASSERT_EQ(val1, val2)
EXPECT_EQ
:如果断言失败,测试继续执行ASSERT_EQ
:如果断言失败,当前测试停止执行
#include <gtest/gtest.h>
#include <iostream>
int add(int a, int b) {
return a + b;
}
TEST(AddTest, PositiveNumbers) {
EXPECT_EQ(add(2, 3), 5); // 这条断言通过
EXPECT_EQ(add(1, 1), 3); // 这条断言失败,但测试继续执行
}
TEST(AddTest, AssertEqual) {
ASSERT_EQ(add(2, 3), 5); // 通过
std::cout<<"测试输出:assert_eq前"<<std::endl;
ASSERT_EQ(add(1, 1), 3); // 失败,当前测试停止
std::cout<<"测试输出:assert_eq后"<<std::endl;
}
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc,argv);
//运行所有测试用例
return RUN_ALL_TESTS();
}
EXPECT_NE(val1, val2)
和ASSERT_NE(val1, val2)
TEST(AddTest, NotEqual) {
EXPECT_NE(add(2, 3), 6); // 通过
EXPECT_NE(add(2, 2), 5); // 通过
ASSERT_NE(add(2, 3), 6); // 通过
ASSERT_NE(add(1, 1), 3); // 失败,测试停止(注意该处是不会打印错误的,直接就退出了)
}
EXPECT_LT(val1, val2)
和ASSERT_LT(val1, val2)
验证val1是否小于val2
TEST(ComparisonTest, LessThan) {
EXPECT_LT(2, 3); // 通过
EXPECT_LT(5, 3); // 失败,测试继续
ASSERT_LT(2, 3); // 通过
ASSERT_LT(5, 3); // 失败,测试停止
}
EXPECT_LE(val1, val2)
和ASSERT_LE(val1, val2)
验证val1是否小于或者等于val2
TEST(ComparisonTest, LessThanOrEqual) {
EXPECT_LE(2, 3); // 通过
EXPECT_LE(3, 3); // 通过
EXPECT_LE(5, 3); // 失败,测试继续
ASSERT_LE(2, 3); // 通过
ASSERT_LE(3, 3); // 通过
ASSERT_LE(5, 3); // 失败,测试停止
}
XPECT_GT(val1, val2)
和ASSERT_GT(val1, val2)
验证 val1
是否大于 val2
TEST(ComparisonTest, GreaterThan) {
EXPECT_GT(3, 2); // 通过
EXPECT_GT(2, 3); // 失败,测试继续
ASSERT_GT(3, 2); // 通过
ASSERT_GT(2, 3); // 失败,测试停止
}
EXPECT_GE(val1, val2)
和ASSERT_GE(val1, val2)
验证 val1
是否大于或等于 val2
TEST(ComparisonTest, GreaterThanOrEqual) {
EXPECT_GE(3, 2); // 通过
EXPECT_GE(3, 3); // 通过
EXPECT_GE(2, 3); // 失败,测试继续
ASSERT_GE(3, 2); // 通过
ASSERT_GE(3, 3); // 通过
ASSERT_GE(2, 3); // 失败,测试停止
}
EXPECT_TRUE(condition)
和ASSERT_TRUE(condition)
验证 condition
是否为 true
TEST(ConditionTest, IsTrue) {
EXPECT_TRUE(2 + 3 == 5); // 通过
EXPECT_TRUE(2 + 3 == 6); // 失败,测试继续
ASSERT_TRUE(2 + 3 == 5); // 通过
ASSERT_TRUE(2 + 3 == 6); // 失败,测试停止
}
EXPECT_THROW(statement, exception)
和ASSERT_THROW(statement, exception)
断言用于验证执行某个语句时是否抛出了特定类型的异常
EXPECT_THROW
:如果没有抛出异常,测试继续执行ASSERT_THROW
:如果没有抛出异常,测试立即停止
#include <gtest/gtest.h>
#include <iostream>
#include <stdexcept>
void throw_exception() {
throw std::runtime_error("An error occurred");
}
TEST(ExceptionTest, ThrowException) {
EXPECT_THROW(throw_exception(), std::runtime_error); // 通过
EXPECT_THROW(throw_exception(), std::invalid_argument); // 失败,测试继续
ASSERT_THROW(throw_exception(), std::runtime_error); // 通过
ASSERT_THROW(throw_exception(), std::invalid_argument); // 失败,测试停止
}
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc,argv);
//运行所有测试用例
return RUN_ALL_TESTS();
}
EXPECT_NO_THROW(statement)
和ASSERT_NO_THROW(statement)
用于验证语句没有抛出异常,参考上面
TEST(ExceptionTest, NoThrow) {
EXPECT_NO_THROW(throw_exception()); // 失败,测试继续
EXPECT_NO_THROW(int x = 5); // 通过
ASSERT_NO_THROW(throw_exception()); // 失败,测试停止
ASSERT_NO_THROW(int x = 5); // 通过
}
动态库编译问题
问题复现
#include<iostream>
#include<gtest/gtest.h>
int add(int x , int y)
{
return x+y;
}
TEST(函数测试,加法函数测试1)
{
//判断最终结果是否为40
ASSERT_EQ(add(20,20),40);
ASSERT_LT(add(10,10),30);
}
// TEST(函数测试, 字符串测试)
// {
// std::string str = "hello gtest";
// ASSERT_EQ(str, std::string("hello gtest")); // 类型一致
// ASSERT_EQ(str, std::string("hello world")); // 比较失败
// }
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc,argv);
//运行所有测试用例
return RUN_ALL_TESTS();
}
main : main.cc
g++ -std=c++17 $^ -o $@ -lgtest
解决思路
无法查找到gtest动态库
重新安装,然后生成动态库
通过源码并进行编译
在构建目录下安装并生成动态库
动态库安装完毕,重新编译程序验证
编译成功,但是运行失败
分析:这个是动态库路径没有正常配置导致的,先通过环境变量,显式的指定动态库路径,尝试是否可以解决问题;先判断路径,然后显式指定
永久性配置动态链接库路径
通过命令将动态库路径加入到系统的动态库链接器配置中
问题解决
反思总结
sudo apt-get install libgtest-dev没有生成动态库的原因
Ubuntu官方的 libgtest-dev的包只提供 gtest的源码,不会自动生成静态库和动态库,这个是提供给使用者根据项目的需要动态决定自己构建动态库
gtest默认是以静态库进行使用,自己手动编译默认生成的也是静态库,如果需要动态库,那么必须显式的启用BUILD_SHARED_LIBS=ON的CMake配置选项
一个Build文件造成静态库和动态库冲突位问题
如果在Build目录中生成了缓存文件,这些缓存文件会固定CMake的构建配置选项,所以如果已经有静态库的缓存文件,此时再使用生成动态库,就会导致动态库使用静态库的缓存,所以最终就会导致错误
解决该问题的办法有两个,其一是给静态库和动态库分别构建一个Build文件夹,其二则是先清理旧的换存然后再生成