Google_Test

这里学习一下相关googleTest的功能。

全文来源于:GoogleTest。笔者只进行翻译和自我理解。

安装与启动

首先我们创建一个属于自己的工作区(文件夹)。创建工作区的部分可以参考 配置 ,不同系统上略有不同但unix类型系统都差不多。windows 是异端!。

接下来撰写我们的cmake文件。首先来安装相关的库。

# 最小版本要求
cmake_minimum_required(VERSION 3.22)
# 自定义debug模式参数。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall")
# 设定编译器和C++标准
set(CMAKE_C_COMPILER "/usr/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 20)
# 项目名。
project(main) include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FetchContent_MakeAvailable(googletest)
set(ENV{HTTP_PROXY} "http://localhost:1080") # 没办法,gfw

然后我们编写一个简单的测试程序

#include <gtest/gtest.h>
// Demonstrate some basic assertions.
TEST(HelloTest, BasicAssertions) {
// Expect two strings not to be equal.
EXPECT_STRNE("hello", "world");
// Expect equality.
EXPECT_EQ(7 * 6, 42);
}

最后增加以下部分开启googletest。

enable_testing()        # 开启测试
add_executable(main main.cpp) # 增加可执行文件和其源文件。
target_link_libraries(
main
GTest::gtest_main
) # 链接gtest动态库。
include(GoogleTest) # 包含头文件。
gtest_discover_tests(main) # 自动寻找测试项目。

从源码安装

git clone https://github.com/google/googletest.git
cd googletest/
mkdir build
cd build
cmake ..
make
sudo make install

cmake 脚本变成:

cmake_minimum_required(VERSION 3.22)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall")

set(CMAKE_C_COMPILER "/usr/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 20) project(main) enable_testing()
find_package(GTest REQUIRED) add_executable(main main.cpp)
target_link_libraries(
main
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(main)

测试的一些基本原则

  • 独立/可重复。
  • 具有良好的结构,可以反应测试代码的结构。
  • 可重用且可移植。
  • 提示足够多的相关问题的信息,当测试失败的时候,可以提示该测试失败的信息,并且继续执行其他部分。
  • 专注于测试的内容而非其他的一些杂项。
  • 足够快。

基本概念

一般而言,googleTest将从断言开始书写。断言将会判断你的一个语句是否是真。

  • 断言的结果一般有三种:

    • (非致命性)失败,(致命性)失败与成功。
    • 当一个致命性失败出现时,当前函数将会中断。否则程序将会继续正常运行。

测试通过断言来验证代码的行为。当测试故障或出现一个(致命性)错误断言时,测试程序中止,否则它将会成功。

一个测试组(test suites)将会包括一个或者多个测试,你可以将测试集合成多个测试组来反应测试代码的结构。多个测试在同一组中采用共享对象和子进程时,可以放入一个test fixture类中。

一个测试程序可以有多个测试组(test suites)。

断言

主要分为两种:ASSERT_*(抛出致命性错误),EXPECT_*(抛出非致命性错误)。前者需要注意可能的内存泄漏问题,因为函数将会提前终止。

我们可以通过 << 来输出错误时我们的报错信息。例如:

EXPECT_EQ(7 * 5, 42) << "The calculation result should be 42!\n";是非致命性报错,因此会继续往下执行到达程序结束。

任何的可以通过ostream输出的方式都可以通过断言输出。

简单测试

创建一个测试:

  1. 使用TEST()宏来定义和命名一个测试函数。这是常用的C++的函数,并且没有返回值。
  2. 在这个函数中,任何合法的C++语句都可以被include,并且采用断言检查值。
  3. 测试结果通过断言进行决定。如果任何断言致命性失败,或者测试程序崩溃,整个测试就将会失败。否则,它将会执行结束。
TEST(TestSuiteName, TestName) {
// Test Body
}

我们可以写出一个简单的阶乘测试

#include <gtest/gtest.h>

template<class T>
T factorial(T n) {
if(n == 1 || n == 0) return 1;
else return factorial(n-1) * n;
} TEST(MyTest, TestFactorialCase) {
// Case statement.
EXPECT_EQ(factorial(0), 1);
EXPECT_EQ(factorial(1), 1);
}
TEST(MyTest, TestFactorialNormal) {
// Some cases.
EXPECT_EQ(factorial(1), 1);
EXPECT_EQ(factorial(2), 2);
EXPECT_EQ(factorial(3), 6);
EXPECT_EQ(factorial(8), 40320);
}

Test Fixtures:多测试中采用相同数据配置

当你发现你在相同数据上写两个/多个测试,并且需要用到相同的数据配置时,可以使用test fixture,这样在不同测试中可以使用相同的对象配置。

创建一个Fixture:

  1. testing::Test中继承一个新的类。从protected部分开始编写。
  2. 在类中,可以声明任意的对象。
  3. 如果必要,书写一个默认的构造函数SetUp()来对每一个测试进行准备。注意拼写!
  4. 如果必要,书写一个析构函数来销毁所有的在构造函数中分配的资源。
  5. 如有必要,构建子程序来告诉你的测试进行共享。

TestSuite采用如下的格式

TEST_F(TestFixtureClassName, TestName) {
// 测试函数体
}

这样我们可以编写示例函数:

#include <gtest/gtest.h>
#include <queue> class QueueTest: public testing::Test {
protected:
std::queue<int> q0, q1, q2;
QueueTest() {
q1.push(1);
q2.push(2);
q2.push(3);
}
};
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(q0.size(), 0);
}
TEST_F(QueueTest, DequeueWorks) {
EXPECT_EQ(q0.empty(), true); int n = q1.front();
EXPECT_EQ(n, 1);
q1.pop();
EXPECT_EQ(q1.size(), 0); n = q2.front();
EXPECT_EQ(n, 2);
q2.pop();
EXPECT_EQ(q2.size(), 1);
}

添加main函数

我们可以将google test集成到main函数中。这样我们可以实现执行其他部分的功能。main函数的一个实例如下:

int main() {
testing::InitGoogleTest();
int status = RUN_ALL_TESTS();
return status;
}

status = 0 代表执行成功,否则其他情况将返回1.

更进一步

接下来将进入更多的技巧,例如复杂的失败信息,传递致命性失败信息,重用和提高测试集合速度,以及采用不同的flags。

更多的断言

  • 显式的成功和失败。

    • SUCCEED(), FAIL()(致命性),ADD_FAILURE(file, line)(非致命性)。ADD_FAILURE_AT()在指定文件和行后增加非致命性信息。
  • 异常断言
    • EXPECT/ASSERT_THROW(statement, exception_type)验证抛出特定类型的错误。

复杂分枝

采用一以下函数来提供比EXPECT_TRUE(statement)更好的消息。

testing::AssertionResult IsEven(int n) {
if ((n % 2) == 0)
return testing::AssertionSuccess();
else
return testing::AssertionFailure() << n << " is odd";
}
// bool IsEven(int n) {
// return (n % 2) == 0;
// }

浮点数比较

采用以下方式来进行简单但是比较全面的比较。

using ::testing::FloatLE;
using ::testing::DoubleLE;
// ...
EXPECT_PRED_FORMAT2(FloatLE, val1, val2);
EXPECT_PRED_FORMAT2(DoubleLE, val1, val2);

[未完待续]

google_test的更多相关文章

  1. protocol buffer c++ python库安装

    c++库安装较简单,不要用源码,还得下载依赖,就被墙了 https://github.com/google/protobuf/releases  下载一个最新的release安装 #protoc -- ...

  2. (原)python中import caffe提示no module named google.protobuf.internal

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5993405.html 之前在一台台式机上在python中使用import caffe时,没有出错.但是 ...

  3. P4语言环境安装(一)前端编译器p4c、后端编译器p4c-bm2-ss

    这个P4安装环境是在2020-2-8安装的,安装环境卡了我好几天,把遇到的问题记录下来,有需要的同学可以参考一下,要是说错了或者有问题的话,评论或mail:guidoahead@163.com联系我都 ...

随机推荐

  1. CF1905C Largest Subsequence 题解

    CF1905C Largest Subsequence 首先考虑如何生成一个字典序最大的子序列.我们先考虑找到字符串中的最大元素,然后在其之后找到第二大的元素,重复这个过程,直到达到序列末尾. 我们可 ...

  2. opengl 学习 之 10 lesson

    opengl 学习 之 10 lesson 简介 透明度 简单来说让设定的透明度起作用. link http://www.opengl-tutorial.org/uncategorized/2017/ ...

  3. amis 怎样将表格中状态格式化显示1和0为是和否

    最近在做一个关于AMIS的,发现好多地方跟原生JS不太一样,也跟vue.angular不一样,做的时候遇到些问题 现将amis 怎样将表格中状态格式化显示1和0为是和否部分代码记录如下: { &quo ...

  4. SciTech-EECS-Power-Battery: 大艺 与 牧田 锂电池 与 动力电池芯 的 规格

    SciTech-EECS-Power-Battery: 大艺 与 牧田 锂电池 与 动力电池芯 的 规格 锂电池模块 额定标称电压: 有的额定电压称: 3.6V/串 * 5串=18V, 有的额定电压称 ...

  5. SciTech-Mathmatics-Analysis: 定积分 求解的“十大公式”

    SciTech-Mathmatics-Analysis: 定积分 求解的"十大公式" 1. Newton-Leibniz formula \(\large \begin{array ...

  6. unity判断LayerMask里面是否包含你想要的Layer

    public bool IsInLayerMask(GameObject obj, LayerMask layerMask) { // 根据Layer数值进行移位获得用于运算的Mask值 int ob ...

  7. Linux CentOS 7系统固定网卡名称和MAC地址操作步骤

    以下是CentOS 7系统中固定网卡名称和MAC地址的详细操作流程,确保ip a或ifconfig显示修改后的结果: ​​一.固定网卡名称​​ ⚙️ ​​方法1:通过udev规则绑定(推荐)​​ ​​ ...

  8. VTK开发笔记(一):VTK介绍,Qt5.9.3+VS2017x64+VTK8.2编译

    前言   主流开源三维三大流派:openGL.osg和vtk,各有优劣,所以根据项目和产品定义的不同,选择合适的方式,本系列开启VTK三维系列教程.  这里注意我们走的是C++技术流,对内存.性能和交 ...

  9. PostgreSQL LIMIT 子句

    PostgreSQL 中的 limit 子句用于限制 SELECT 语句中查询的数据的数量. 带有 LIMIT 子句的 SELECT 语句的基本语法如下: 下面是 LIMIT 子句与 OFFSET 子 ...

  10. vscode 设置终端无效

    The Windows profiles to present when creating a new terminal via the terminal dropdown. Set to null ...