GoogleTest 入门(1) 官网文档浏览

本文介绍了如何使用Googletest进行C++单元测试,包括安装、CMake集成、基本断言和测试结构。强调了单元测试的独立性、可重复性和组织结构,以及GoogleTest中的术语和宏定义。通过实例展示了TEST_F的用法,以及如何编写测试固定装置(TestFixtures)。文章最后给出了一个完整的Googletest测试用例模板。
摘要由CSDN通过智能技术生成

0. 前言

  • 要转型成为C++工程师,要走的路还很长啊……最近写了不少C++代码和项目,单元测试都是自己随便写写,不成体系,希望能够了解下业界的写法,自己也学一学。

  • 单元测试框架好像没有什么悬念,就是googletest了。

  • 官方资料阅读

    • 官方资料:Github文档

    • GooglgTest是由之前两个项目 GoogleTest 和 GoogleMock 组成,所以在文档中,基本上也可以分为 GoogleTest 和 Mocking 两个部分。

    • 官网文档目录如下:

image-20210623000236584

1. Getting Started

  • 主要内容

    • GTest的安装平台要求
    • Bazel 引入 GTest
    • CMake 引入 GTest,对应文档
      • 修改CMakeLists.txt
      • 添加源文件
  • CMakeLists.txt 相关内容主要包括

    • 引入 GTest:教程里比较骚,用的是 CMake 的 FetchContent_Declare/FetchContent_MakeAvailable,直接从github下载源码并解析。
    • 开启Test,引入GTest头文件、so以及相关测试源码。
  • 测试源码:就是一些GTest的断言。

2 Googletest Primer

  • 官方推荐的基础教程,网址是这里

  • GoogleTest 有什么作用

    • 测试应该是独立,且可重复的。
    • 测试应该有很好的组织结构,能反映被测试代码的总体结构。
    • 测试应该可移植、可复用
    • 当测试失败时,应该提供足够的信息
    • 单元测试的速度应该足够快
  • GoogleTest 中用到的一些术语以及基本概念

    • assertions:断言,判断一个条件是否为真。断言的结果可以是 success/non fatal failure/fatal failure,如果是 fatal failure 则就会跳出程序。
    • Test:使用 assertions 来判断程序是否运行成功。
    • Test Case:从现在来看,应该是 Test 的同义词。
      • 然而,由于历史原因,GoogleTest中以前Test Case其实是 Test Suite的含义,但现在正在往 Test Suite 上转型。
    • Test Suite:包含一个或多个 Test。应该通过 Test Suite 来管理 Test,并反映程序的总体结构。
    • Test program:包含多个 Test Suites。
  • Assertions

    • GoogleTest中的断言,是一系列宏定义,通过一个断言来判断类、函数的行为是否符合预期。
    • 每一类断言都有两个对应的宏,一个形如 ASSERT_*,如果断言报错则中断当前函数;一个形如 EXCEPT_*,如果报错不会中断当前函数。
    • 如何构建自定义错误消息,就是在宏后面添加 << 并跟上错误内容,比如 ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
  • 编写 TEST

    • 注意,这里的TEST指的是宏,也就是上面基本概念中的 Test Case。
    • 基本语法以及举例如下
      • 两个参数必须是合法的C++变量名
TEST(TestSuiteName, TestName) {
  ... test body ...
}

// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
  EXPECT_EQ(Factorial(0), 1);
}

// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
  EXPECT_EQ(Factorial(1), 1);
  EXPECT_EQ(Factorial(2), 2);
  EXPECT_EQ(Factorial(3), 6);
  EXPECT_EQ(Factorial(8), 40320);
}
  • 如果若干个Test Case 要公用参数,按就需要使用 Test Fixtures
    • 总体流程如下:
      • 构建一个类,继承 ::testing::Test
      • 需要继承的成员变量(测试中用到的各种参数)都放在 protected 里面
      • 使用 SetUp 作为初始化参数的方法。
      • 如果需要,也可以定义成员变量,在各种测试中复用。
      • 使用 TEST_F 解决
class QueueTest : public ::testing::Test {
 protected:
  void SetUp() override {
     q1_.Enqueue(1);
     q2_.Enqueue(2);
     q2_.Enqueue(3);
  }

  // void TearDown() override {}

  Queue<int> q0_;
  Queue<int> q1_;
  Queue<int> q2_;
};

TEST_F(QueueTest, IsEmptyInitially) {
  EXPECT_EQ(q0_.size(), 0);
}

TEST_F(QueueTest, DequeueWorks) {
  int* n = q0_.Dequeue();
  EXPECT_EQ(n, nullptr);

  n = q1_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 1);
  EXPECT_EQ(q1_.size(), 0);
  delete n;

  n = q2_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 2);
  EXPECT_EQ(q2_.size(), 1);
  delete n;
}
  • 启动测试

    • 基本流程:
      • 通过TEST 以及 TEST_F 注册所有测试。注意,不需要另外罗列所有测试。
      • 通过 RUN_ALL_TESTS() 执行测试。返回值为0则表示成功,1表示失败。
  • 一个实例

#include "this/package/foo.h"

#include "gtest/gtest.h"

namespace my {
namespace project {
namespace {

// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
 protected:
  // You can remove any or all of the following functions if their bodies would
  // be empty.

  FooTest() {
     // You can do set-up work for each test here.
  }

  ~FooTest() override {
     // You can do clean-up work that doesn't throw exceptions here.
  }

  // If the constructor and destructor are not enough for setting up
  // and cleaning up each test, you can define the following methods:

  void SetUp() override {
     // Code here will be called immediately after the constructor (right
     // before each test).
  }

  void TearDown() override {
     // Code here will be called immediately after each test (right
     // before the destructor).
  }

  // Class members declared here can be used by all tests in the test suite
  // for Foo.
};

// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
  const std::string input_filepath = "this/package/testdata/myinputfile.dat";
  const std::string output_filepath = "this/package/testdata/myoutputfile.dat";
  Foo f;
  EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0);
}

// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
  // Exercises the Xyz feature of Foo.
}

}  // namespace
}  // namespace project
}  // namespace my

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值