基本了解

google提供的一个C++测试框架,主要就是简化测试单元的书写,具有高效、灵活可拓展的特点

主要特点

  • 简单易用:gtest 提供了清晰且易于使用的 API,便于开发者快速编写单元测试。
  • 丰富的断言支持:gtest 提供了多种断言(assertion)来验证不同类型的条件(如 EXPECT_EQASSERT_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):期望 val1val2 相等(不等时记录失败,但继续执行)。
    • ASSERT_EQ(val1, val2):期望 val1val2 相等(不等时会终止当前测试)。
    • 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文件夹,其二则是先清理旧的换存然后再生成

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部