GTest 总结_gtest单元测试

GTest 总结_gtest单元测试GoogleC++单元测试框架(简称Gtest),可在多个平台上使用(包括Linux,MacOSX,Windows,Cygwin和Symbian),它提供了丰富的断言、致命和非致命失败判断,能进行值参数化测试、类型参数化测试、“死亡测试”。1断言一般的,要测试一个方法(函数)是否是正常执行的,可以提供一些输入数据,在调用这个方法(函数)后,得到输出数据,然后检查输出的数据是否与我们期望的结果是一致的,若一致,则说明这个方法的逻辑是正确的,否则,就有问题。在对输出结果进行检查(chec.

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Google C++单元测试框架(简称Gtest),可在多个平台上使用(包括Linux, Mac OS X, Windows, Cygwin和Symbian),它提供了丰富的断言、致命和非致命失败判断,能进行值参数化测试、类型参数化测试、“死亡测试”。

1断言

一般的,要测试一个方法(函数)是否是正常执行的,可以提供一些输入数据,在调用这个方法(函数)后,得到输出数据,然后检查输出的数据是否与我们期望的结果是一致的,若一致,则说明这个方法的逻辑是正确的,否则,就有问题。  在对输出结果进行检查(check)时,Gtest为我提供了一系列的断言(assertion)来进行代码测试,这些宏有点类似于函数调用。当断言失败时Gtest将会打印出assertion时的源文件和出错行的位置,以及附加的失败信息。这些输出的附加信息用户可以直接通过“<<”在这些断言宏后面。

Gtest中,断言的宏可以理解为分为两类,一类是ASSERT系列,一类是EXPECT系列。

ASSERT_* 系列的断言(Fatal assertion),当检查点失败时,退出当前函数(注意:并非退出当前案例)。

EXPECT_* 系列的断言(Nonfatal assertion),当检查点失败时,继续执行下一个检查点(每一个断言表示一个测试点)。

通常情况应该首选使用EXPECT_,因为ASSERT_*在报告完错误后不会进行清理工作,有可能导致内存泄露问题。

1.1布尔型检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_TRUE(condition);

EXPECT_TRUE(condition);

condition is true

ASSERT_FALSE(condition);

EXPECT_FALSE(condition);

condition is false

1.2二值检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_EQ(expected, actual);

EXPECT_EQ(expected, actual);

expected == actual

ASSERT_NE(val1, val2);

EXPECT_NE(val1, val2);

val1 != val2

ASSERT_LT(val1, val2);

EXPECT_LT(val1, val2);

val1 < val2

ASSERT_LE(val1, val2);

EXPECT_LE(val1, val2);

val1 <= val2

ASSERT_GT(val1, val2);

EXPECT_GT(val1, val2);

val1 > val2

ASSERT_GE(val1, val2);

EXPECT_GE(val1, val2);

val1 >= val2

一般来说二进制比较,都是对比其结构体所在内存的内容。C++大部分原生类型都是可以使用二进制对比的。但是对于自定义类型,我们就要定义一些操作符的行为,比如=、<等。

1.3字符串检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_STREQ(expected_str, actual_str);

EXPECT_STREQ(expected_str,actual_str);

the two C strings have the same content

ASSERT_STRNE(str1, str2);

EXPECT_STRNE(str1, str2);

the two C strings have different content

ASSERT_STRCASEEQ(expected_str, actual_str);

EXPECT_STRCASEEQ(expected_str, actual_str);

the two C strings have the same content, ignoring case (忽略大小写)

ASSERT_STRCASENE(str1, str2);

EXPECT_STRCASENE(str1, str2);

the two C strings have different content, ignoring case (忽略大小小)

*STREQ*和*STRNE*同时支持char*和wchar_t*类型的,*STRCASEEQ*和*STRCASENE*却只接收char*

1.4异常检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_THROW(statement, exception_type);

EXPECT_THROW(statement, exception_type);

statement throws an exception of the given type

ASSERT_ANY_THROW(statement);

EXPECT_ANY_THROW(statement);

statement throws an exception of any type

ASSERT_NO_THROW(statement);

EXPECT_NO_THROW(statement);

statement doesn’t throw any exception

1.5浮点检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_FLOAT_EQ(expected, actual);

EXPECT_FLOAT_EQ(expected, actual);

the two float values are almost equal

ASSERT_DOUBLE_EQ(expected, actual);

EXPECT_DOUBLE_EQ(expected, actual);

the two double values are almost equal

在对比数据方面,我们往往会讨论到浮点数的对比。因为在一些情况下,浮点数的计算精度将影响对比结果,所以这块都会单独拿出来说。GTest对于浮点数的对比也是单独的

1.6相近值检查

Fatal assertion

Nonfatal assertion

Verifies

ASSERT_NEAR(val1, val2, abs_error);

EXPECT_NEAR(val1, val2, abs_error);

the difference between val1 and val2 doesn’t exceed the given absolute error

2 宏测试

2.1 TEST宏        

TEST宏是一个很重要的宏,它构成一个测试特例,它的原型是

GTest 总结_gtest单元测试

 TEST宏的第一个参数是test_suite_name(测试套件名),第二个参数是test_name(测试特例名)。测试套件名和测试特例名(也叫测试名)的区别和联系:

测试套件(Test Case)是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求,测试特例是测试套件下的一个(组)测试。

GTest 总结_gtest单元测试

GTest 总结_gtest单元测试

以上述代码为例,三段TEST宏构成的是一个测试套件——测试套件名是FactorialTest(阶乘方法检测,测试Factorial函数),该用例覆盖了三种测试特例——Negative、Zero和Positive——即检测输入参数是负数、零和正数这三种特例情况。

对于测试套件名和测试特例名,不能有下划线(_)。因为GTest源码中需要使用下划线把它们连接成一个独立的类名

GTest 总结_gtest单元测试

这样也就要求,我们不能有相同的“测试套件名和特例名”的组合——否则类名重合。

测试套件名和测试特例名的分开,使得我们编写的测试代码有着更加清晰的结构——即有相关性也有独立性。相关性是通过相同的测试套件名联系的,而独立性通过不同的测试特例名体现的。

2.2 TEST_F 宏

测试PositiveNum这个类。

GTest 总结_gtest单元测试

使用TEST_F前需要创建一个固件类,继承于::testing::Test类。在类内部使用public或者protected描述其成员,为了保证实际执行的测试子类可以使用其成员变量。在构造函数或者继承于::testing::Test类中的SetUp方法中,可以实现我们需要构造的数据。在析构函数或者继承于::testing::Test类中的TearDown方法中,可以实现一些资源释放的代码。“构造函数/析构函数”和“SetUp/TearDown”的选择,对于什么时候选择哪对,没有统一的标准。一般来说就是构造/析构函数里忌讳做什么就不要在里面做,比如抛出异常等。

GTest 总结_gtest单元测试

TEST_F宏和TEST宏的实现非常接近,只是TEST_F宏的封装更加开放一些,所以对TEST宏的功能多了一些扩展。他的原型是:

GTest 总结_gtest单元测试

第一个参数为测试套件名(与创建的固件类名一致),第二个为测试名,可任意取。

    GTest 总结_gtest单元测试

GTest 总结_gtest单元测试

第一个测试中,修改了pn1成员数据值为-2,测试结果为ok,紧接着第二个测试结果也是ok(如果测试一的修改会影响测试二,结果应为fail)。所有局部测试都是正确的,验证了固件类中数据的恒定性,每个测试特例都是要新建一个新的PositiveNumTest对象,并在该测试特例结束时销毁它,这样可以保证数据的干净。

TEST_F与TEST的区别是,TEST_F提供了一个初始化函数(SetUp)和一个清理函数(TearDown),在TEST_F中使用的变量可以在初始化函数SetUp中初始化,在TearDown中销毁,并且所有的TEST_F是互相独立的,都是在初始化以后的状态开始运行,一个TEST_F不会影响另一个TEST_F所使用的数据,多个测试场景需要相同数据配置的情况,用 TEST_F。

2.3 TEST_P宏

在设计测试案例时,经常需要考虑给被测函数传入不同的值的情况。我们之前的做法通常是写一个通用方法,然后编写在测试案例调用它。即使使用了通用方法,这样的工作也是有很多重复性的。

测试IsPrime这个函数(判断输入值是否为质数)。

GTest 总结_gtest单元测试

用TEST这个宏,需要编写如下的测试案例,每输入一个值就需要写一个测试点,这还只是在一个测试中,如果把每个测试点单独创建一个测试,工作量就更大。

GTest 总结_gtest单元测试

 使用TEST_P这个宏,对输入进行参数化,就简单很多。

GTest 总结_gtest单元测试

GTest 总结_gtest单元测试

创建一个参数化类IsPrimeParamTest。继承自TestWithParam这个模板类,TestWithParam又继承Test和WithParamInterface<T>。

GTest 总结_gtest单元测试

WithParamInterface<T>这个模板类定义了ParamType,用于参数型别推导,提供GetParam()函数,用于TEST_P宏里的实现逻辑获取参数。

GTest 总结_gtest单元测试

使用INSTANTIATE_TEST_CASE_P这宏来告诉gtest你要测试的参数范围:

GTest 总结_gtest单元测试

第一个参数PARAM是测试案例的前缀,可以任意取。

第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同,如:IsPrimeParamTest

第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:

Range(begin,end[,step])

范围在begin~end之间,步长为step,不包括end

Values(v1, v2, …, vN)

v1,v2到vN的值

ValuesIn(container) /ValuesIn(begin, end)

从一个C类型的数组或是STL容器,或是迭代器中取值

Bool()

取false 和 true 两个值

Combine(g1, g2, …, gN)

它将g1,g2,…gN进行排列组合,g1,g2,…gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。

TEST_P中两个参数,第一个为测试套件名(与创建的测试类名一致),第二个为测试特例名称。

GTest 总结_gtest单元测试

3. 预处理事件机制

gtest 提供了多种预处理事件机制,非常方便我们在测试之前或之后做一些操作。

1. 全局的,所有测试执行前后。

2. TestSuite级别的,在某测试套件中第一个测试前,最后一个测试执行后。

3. TestCase级别的,每个测试前后。

3.1全局事件

要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。

1. SetUp()方法在所有案例执行前执行

2. TearDown()方法在所有案例执行后执行

GTest 总结_gtest单元测试

还需要在main函数中通过调用testing::AddGlobalTestEnvironment这个函数将事件挂进来,也就是说,我们可以写很多个这样的类,然后将他们的事件都挂上去,AddGlobalTestEnvironment这个函数要放在RUN_ALL_TEST之前。

GTest 总结_gtest单元测试

 GTest 总结_gtest单元测试

3.2 TestSuites事件

需要写一个类,继承testing::Test,然后实现两个静态方法

1. SetUpTestCase() 方法在第一个TestCase之前执行

2. TearDownTestCase() 方法在最后一个TestCase之后执行

GTest 总结_gtest单元测试

 GTest 总结_gtest单元测试

3.3 TestCase事件

TestCase事件是挂在每个案例执行前后的,实现方式和Test’Suites的几乎一样,不过需要实现的是SetUp方法和TearDown方法:

1. SetUp()方法在每个TestCase之前执行

2. TearDown()方法在每个TestCase之后执行。

GTest 总结_gtest单元测试

 GTest 总结_gtest单元测试

 

4. 测试用例运行入口

    GTest 总结_gtest单元测试

RUN_ALL_TESTS()这个宏,从名字上来看,就是运行所有的测试用例,这才是我们运行测试用例的真正入口。它的原型是:

GTest 总结_gtest单元测试 

RUN_ALL_TESTS()是一个宏,将其实现为函数,在这里,调用了UnitTest单例的Run函数,看调用过程,可以看到,依次调用的过程是

1.UnitTest::Run()

2. UnitTestImpl::RunAllTests()

3. TestCase::Run()

4. TestInfo::Run()

5. Test::Run()

5. 参考文档

【1】google mock 介绍

【2】google test 介绍 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/187864.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 浅谈ViewState[通俗易懂]

    浅谈ViewState[通俗易懂]一、什么是ViewState二、使用

    2022年7月21日
    12
  • python进程

    python进程

    2021年9月13日
    53
  • matlab多元函数极值_matlab求三元函数的极值

    matlab多元函数极值_matlab求三元函数的极值matlab求解二元函数极值命令:1、x=fminsearch(fun,x0)或x=fminunc(fun,x0)求极小值点x,初值选为x02、[x,fmin]=fminsearch(fun,x0)或[x,fmin]=fminunc(fun,x0)3、fminsearch采用单纯形法,fminunc采用牛顿法除了fminsearch和fminunc这两种命令外,建立函数还可以用不同的方法

    2025年9月26日
    5
  • OSI模型「建议收藏」

    OSI模型「建议收藏」定义开放式系统互联通信参考模型(OpenSystemInterconnectionReferenceModel,缩写为OSI),简称为OSI模型。该模型是由ISO(国际标准化组织)定义,是个灵活稳健和可互操作的模型。目的规范不同系统的互联标准,使两个不同的系统能够较容易通信,而不需要改变底层的硬件和软件的逻辑。优点每层功能简单单一,标准化允许各种类型的网络硬件和软件相互通信…

    2025年8月14日
    1
  • sntp协议简介

    sntp协议简介SNTP协议主要是通过记录客户端向服务器发送数据包时的时间戳t1,服务器端接收到该数据包时的时间戳t2,服务器向客户端回应时的时间戳t3和最后客户端接收到服务器回应时的时间戳t4来计算客户端时间和服务器端时间的偏差,从而进行校时操作

    2025年7月5日
    3
  • 什么是互质_数组转集合list

    什么是互质_数组转集合list给定 n 个正整数,将它们分组,使得每组中任意两个数互质。至少要分成多少个组?输入格式第一行是一个正整数 n。第二行是 n 个不大于10000的正整数。输出格式一个正整数,即最少需要的组数。数据范围1≤n≤10输入样例:614 20 33 117 143 175输出样例:3#include<bits/stdc++.h>using namespace std;const int N = 1e2 + 10;int a[N],g[N][N];int n;int

    2022年8月9日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号