GTest基础学习-04-第3个单元测试-测试夹具test fixture

2023-11-09

这篇来学习一下Gtest中更高级一些的特性test fixture,测试夹具的基本上使用。什么的场景需要使用到测试夹具呢?测试夹具是哪个宏,这篇来学习这个主题。

 

1.什么叫test fixture

什么是测试夹具,这个概念在任何xUnit系列的单元测试框架都会出现。一般是指,所有的测试用例都可以共享的步骤,例如初始化和事后清理操作,能提供这个功能的对象叫test fixture。

在test fixture是这样使用的,我们需要单独写一个类并且继承testing::Test,如果有必要都需要实现SetUp()和TearDown()函数,当然这两个至少有一个需要实现,不然我们不会去使用test fixture这个功能。在SetUp()函数中一般写一些初始化操作,例如测试对象的创建,对象的成员变量的初始化等,在TearDown()一般用来集中清除资源操作,例如销毁在SetUp()中创建的被测试对象。

 

2.测试夹具使用

sample03.h代码

#ifndef GTEST_SAMPLES_SAMPLE03_INL_H_
#define GTEST_SAMPLES_SAMPLE03_INL_H_

#include <stddef.h>


// Queue类是一个简单的队列,内部是基于单链表实现
//
// 元素数据类型必须支持拷贝构造
template <typename E>  // E 是元素的类型。使用了模板类
class Queue;

// QueueNode 是Queue对象中的一个结点, 存储元素E和指向下一个结点的指针
template <typename E>  // E 是元素的类型。使用了模板类
class QueueNode {
	friend class Queue<E>;

public:
	// 获取结点中的元素
	const E& element() const { return element_; }

	// 获取下一个结点
	QueueNode* next() { return next_; }
	const QueueNode* next() const { return next_; }

private:
	// 创建一个结点,元素是参数element,下一个结点的指针设置为NULL
	explicit QueueNode(const E& an_element)
		: element_(an_element), next_(nullptr) {}

	// 这里禁用默认的赋值操作和构造
	const QueueNode& operator = (const QueueNode&);
	QueueNode(const QueueNode&);

	E element_;
	QueueNode* next_;
};

template <typename E>  // E 是可以任意类型
class Queue {
public:
	// 创建一个空的队列
	Queue() : head_(nullptr), last_(nullptr), size_(0) {}

	// 析构函数 清空队列
	~Queue() { Clear(); }

	// 清空队列函数
	void Clear() {
		if (size_ > 0) {
			// 1. 删除每一个结点
			QueueNode<E>* node = head_;
			QueueNode<E>* next = node->next();
			for (; ;) {
				delete node;
				node = next;
				if (node == nullptr) break;  //跳槽循环在这行
				next = node->next();
			}

			// 2.重置成员变量,队列大小为0,头结点和尾结点都设置为空指针
			head_ = last_ = nullptr;
			size_ = 0;
		}
	}

	// 获取队列元素个数
	size_t Size() const { return size_; }

	// 获取队列头部元素, 如果队列为空返回NULL
	QueueNode<E>* Head() { return head_; }
	const QueueNode<E>* Head() const { return head_; }

	// 获取队列尾部元素, 如果队列为空返回NULL
	QueueNode<E>* Last() { return last_; }
	const QueueNode<E>* Last() const { return last_; }

	// 往队列尾部插入一个元素,使用拷贝构造创建这个元素并存储在队列中 
	//对队列中的元素所做的更改不会影响源对象,反之亦然。
	void Enqueue(const E& element) {
		QueueNode<E>* new_node = new QueueNode<E>(element);

		if (size_ == 0) {
			head_ = last_ = new_node;
			size_ = 1;
		}
		else {
			last_->next_ = new_node;
			last_ = new_node;
			size_++;
		}
	}

	// 删除头部元素并返回这个元素,如果队列为空,返回NULL
	E* Dequeue() {
		if (size_ == 0) {
			return nullptr;
		}

		const QueueNode<E>* const old_head = head_;
		head_ = head_->next_;
		size_--;
		if (size_ == 0) {
			last_ = nullptr;
		}

		E* element = new E(old_head->element());
		delete old_head;

		return element;
	}

	// 提供一个函数,遍历队列中每一元素,调用这个函数,返回结果存储在一个新的队列,源队列对象不受影响
	template <typename F>
	Queue* Map(F function) const {
		Queue* new_queue = new Queue();
		for (const QueueNode<E>* node = head_; node != nullptr;
			node = node->next_) {
			new_queue->Enqueue(function(node->element()));
		}

		return new_queue;
	}

private:
	QueueNode<E>* head_;  // 队列头结点
	QueueNode<E>* last_;  // 队列尾结点
	size_t size_;  // 队列元素个数

	// 这里不允许复制队列.
	Queue(const Queue&);
	const Queue& operator = (const Queue&);
};

#endif  // GTEST_SAMPLES_SAMPLE03_INL_H_

 

TestSample03.cpp代码

//在这个例子中,我们使用Gtest中更高级一点的特性,叫test fixture, 一般翻译测试夹具
//
// 测试夹具是用来放置对象和函数,并共享给所有的测试用例在一个测试cpp文件中
// 使用测试夹具能够避免测试代码重复,特别是哪些每个测试都需要用到的初始化和清除操作
//
//测试从代码共享的意义上共享的是测试夹具,而不是数据共享。
//每个测试都有自己的最新副本夹具。 您不能期望一次测试修改的数据是传递给另一个测试,这是一个坏主意.
//
// 这么设计的原因是保持测试的独立性和可重复性  
// 一个测试不能受其他的测试失败而导致失败
//如果一个测试依赖于另一个测试,这两个测试应该是被看作一个大的测试
//
// 响应测试成功或失败的宏(例如 EXPECT_TRUE, FAIL, 等)需要知道当前的测试是什么
// 当Google test打印测试结果,如果遇到失败,打印结果会告诉失败是哪一个测试
//从技术上讲,这些宏会调用Test类的成员函数。 因此,您不能在全局函数中使用他们。
//这就是为什么您应该放置测试子例程在测试夹具中。
//

#include "sample03.h"
#include "gtest/gtest.h"
namespace {
	// 想要使用测试夹具,需要定义一个类并继承testing::Test 
	class QueueTestSmpl3 : public testing::Test {
	protected:  // 这里使用保护关键字,成员都受访问保护,可以从子类中访问到父类受保护的成员

	// 每个TEST宏的测试在开始运行之前都会调用virtual void SetUp() 
	//应该实现这个SetUp(),例如一些变量初始化,如果用不到就不需要提供SetUp()
				
	void SetUp() override {
		q1_.Enqueue(1);
		q2_.Enqueue(2);
		q2_.Enqueue(3);
	}

	// 每个TEST宏的测试在结束之前都会调用virtual void TearDown() 
	// 你应该定义在TearDown中做哪些清除操作,否则不应该提供这个TearDown函数
	//
	// virtual void TearDown() {
	// }

	// 一个帮助函数,有些测试需要用到
	static int Double(int n) {
		return 2 * n;
	}

	// 一个帮助函数,为了测试 Queue::Map().
	void MapTester(const Queue<int> * q) {
		// 新建一个对象,队列中每一个元素都是q中元素的两倍大小
		const Queue<int> * const new_q = q->Map(Double);

		// 确认新的队列大小和q是一样大
		ASSERT_EQ(q->Size(), new_q->Size());

		// 确认两个队列之间元素的关系
		for (const QueueNode<int>*n1 = q->Head(), *n2 = new_q->Head();
			n1 != nullptr; n1 = n1->next(), n2 = n2->next()) {
			EXPECT_EQ(2 * n1->element(), n2->element());
		}

		delete new_q;
	}

		// 声明接下来你想用到的几个变量
		Queue<int> q0_;
		Queue<int> q1_;
		Queue<int> q2_;
	};

	// 当你有需要测试夹具( fixture翻译为夹具),需要使用 TEST_F宏编写测试用例,不用TEST宏

	// 测试默认构造函数
	TEST_F(QueueTestSmpl3, DefaultConstructor) {
		// 可以访问元素使用TEST_IF
		EXPECT_EQ(0u, q0_.Size());
	}

	// 测试 Dequeue().
	TEST_F(QueueTestSmpl3, Dequeue) {
		int * n = q0_.Dequeue();
		EXPECT_TRUE(n == nullptr);

		n = q1_.Dequeue();
		ASSERT_TRUE(n != nullptr);
		EXPECT_EQ(1, *n);
		EXPECT_EQ(0u, q1_.Size());
		delete n;

		n = q2_.Dequeue();
		ASSERT_TRUE(n != nullptr);
		EXPECT_EQ(2, *n);
		EXPECT_EQ(1u, q2_.Size());
		delete n;
	}

	// 测试函数Queue::Map() 
	TEST_F(QueueTestSmpl3, Map) {
		MapTester(&q0_);
		MapTester(&q1_);
		MapTester(&q2_);
	}
}  // namespace

在拷贝我的代码过程需要注意,我在每个cpp文件都右键-属性-预编译头中选择了不使用预编译头。

点击生成解决方案,查看gtest的运行输出结果

红圈这几个测试结果是本篇关于test fixture的用例运行结果,注意看倒数第3行,Global test environment tear-down,这个gtest在运行全部测试用例的时候,内部也使用了TearDown()这个机制。

 

3.总结

这篇重点是介绍学习test fixture的基本使用。被测试的对象是一个自定义的队列数据结构的MyQueue类。测试代码中用到了new开辟内存空间和delete删除内存空间,还有模板类的定义。

1.使用TEST_F(测试夹具名称,测试用例名称)

这个测试夹具名称一般就是我们在cpp文件中提前写的自定义类的名称,这个类是必须继承testing::Test

 

本篇就新使用到了几个测试断言宏

ASSERT_EQ	//强断言 两个对象是否相等
ASSERT_TRUE	//强断言,表达式或函数返回值是不是true

这个看起来和前面的EXPECT_EQ和EXPECT_TRUE是一样的作用,很自然,我们就会去想ASSER和EXPECT有什么区别。

 

4.ASSERT和EXPECT的区别

我们在gtest中光标定位在ASSERT_TURE,按下键盘F12,可以看到定义这个方法的代码如下

        通过对比ASSERT_TRUE和EXPECT_TRUE中调用代码的实现,发现两个断言宏的根本区别是在于NONFATAL 和FATAL的区别。上面可以看到EXPECT是调用NONFATAL,而ASSERT是调用FATAL实现。在不继续看代码之前,我们先搞清楚FATAL这个英文单词的意思,翻译过来就是致命。也就是ASSERT走的是致命失败,而EXPECT走的是非致命失败。

        接着分别来看GTEST_NONFATAL_FAILURE_GTEST_FATAL_FAILURE_的内部实现

上面我们点击右侧TestPartResult这个接口,点击F12。

马上就接近真相,通过红圈两个枚举的注释我们得到了答案。

ASSERT_TRUE :如果失败,测试应该被终止

EXPECT_TRUE:如果失败,测试可以继续往下运行

根据这个结论,但是我们当前的水平不好写代码去验证,因为gtest的运行报告不会显示我们自己写的std::cout语句的打印数据。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GTest基础学习-04-第3个单元测试-测试夹具test fixture 的相关文章

  • 如何使 Windows 窗体的关闭按钮不关闭窗体但使其不可见?

    该表单有一个 NotifyIcon 对象 当用户单击 关闭 按钮时 我希望表单不关闭而是变得不可见 然后 如果用户想再次查看该表单 可以双击系统托盘中的图标 如果用户想关闭表单 可以右键单击该图标并选择 关闭 有人可以告诉我如何使关闭按钮不
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • 如何衡量两个字符串之间的相似度? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 给定两个字符串text1 and text2 public SOMEUSABLERETURNTYPE Compare string t
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • CGAL计算几何算法库安装和使用(一)

    CGAL是使用C 开发的计算几何算法库 提供Delaunay三角网 网格生成 多边形 以及各种几何处理算法 应用领域 计算机图形学 科学可视化 计算机辅助设计与建模 地理信息系统 分子生物学 医学影像学 机器人学和运动规划 和数值方法 1
  • KVM同步脏页原理

    文章目录 硬件基础 SPTE 硬件要素 工作流程 PML 硬件要素 工作流程 数据结构 用户态 内核态 API 脏页开启 脏页获取 流程 使能记录 记录脏页 流程图 具体过程 获取脏页 流程图 具体过程 实验 QEMU在内存迁移阶段首先会标
  • Struts2框架验证

    struts2有框架验证 我这边主要说的是XML配置的struts2的框架验证 继承validate方法的验证还是比较容易的 至于有人用注解来验证不怎么常见我也不讲了 感觉好多东西总结的都会有注解来掺和一脚 比如spring注入方式 最常见
  • Python全系列教程:超详细1小时学会Python,太简单了

    1 Hello world 安装完Python之后 打开IDLE Python GUI 该程序是Python语言解释器 你写的语句能够立即运行 我们写下一句著名的程序语句 并按回车 你就能看到这句被K R引入到程序世界的名言 在解释器中选择
  • UFT 自带两个经典sample航空订票应用程序

    大家知道UFT是QTP的升级换代产品 一定保留上一版系统原有的一些的痕迹 比如经典的Flights应用 安装路径 D Program Files x86 Micro Focus Unified Functional Testing samp
  • 单片机定时器/计数器、中断和串口控制位

    一 定时器 计数器 1 定时器控制寄存器 TCON TCON TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 TF1 TF0 定时器 计数器中断请求标志位当定时器计数满溢出回零时 有硬件置位 并可申请中断 当CPU响应中断并
  • C语言:(含大量图解)你真的了解结构体吗?

    文章目录 结构体 结构体的定义 结构体大小计算 结构体的对齐规则 关于对齐规则的解释 为什么C语言要这样进行大小设定 平台移植原因 追求高性能 修改默认对齐数 结构体传参问题 结构体 结构体的定义 结构体是一些值的集合 这些值被称为成员变量
  • 【RPC】RPC的序列化方式

    序列化 网络传输的数据必须是二进制数据 但调用方请求的出入参数都是对象 对象是不能直接在网络中传输的 所以我们需要提前把它转成可传输的二进制 并且要求转换算法是可逆的 这个过程我们一般叫做 序列化 这时 服务提供方就可以正确地从二进制数据中
  • 小程序——wxml组件和wxss适配

    一 和以往代码区别 wxml html zhuiy css view div text文字 加入这个可以长按选中 否则不能复制 image img button button form form input input label labe
  • Leetcode1333.餐厅过滤器——使用stream流

    文章目录 引入 本题题解 后记 int Integer List的互相转化 引入 在上周周赛中 有这么一道题 1333 餐厅过滤器 给你一个餐馆信息数组 restaurants 其中 restaurants i idi ratingi ve
  • Java远程调试原理与运用

    Java远程调试的原理是两个VM之间通过debug协议进行通信 然后以达到远程调试的目的 两者之间可以通过socket进行通信 首先被debug程序的虚拟机在启动时要开启debug模式 启动debug监听程序 jdwp是Java Debug
  • c语言——链表——多项式相加

    例题详解 一个多项式可以表示为二元组序列 a1 e1 a2 e2 an en 其中ai表示第i项的系数 非零值 ei表示第i项的指数 编写函数建立多项式链表实现一个多项式的输入 按指数从高到低有序 返回链表的头指针 3 编写函数实现两个多项
  • 【Kaggle】关于Kaggle永久保存Output & 如何关闭页面后在Kaggle后台运行程序的问题

    其实在创建一个notebook的时候上面的说明的代码已经讲到了 需要创建一个new version才能永久保存Output结果 否则就是临时保存 关掉页面就会删除 This Python 3 environment comes with m
  • 2023mothercup妈妈杯数学建模挑战赛思路

    先占坑 本人于2019年开始接触数学建模 参加了大大小小几十场数学建模比赛 本次mothercup也会持续陪跑 为大家提供免费的文字思路和视频思路 后续还有代码和参考文章等 2023年Mathorcup数学建模竞赛A题 比赛开始后第一时间更
  • swift:使用cocoapods引入Alamofire

    1 打开终端 Terminal 安装cocoapods 回车运行 抛出如下的异常 上网查了一下 这是墙外的网站 我们墙内的访问不了 这时候我们就要更换cocoapods的来源 如果gem的版本太旧 就执行如下命令更新一下gem 以下是更新成
  • vue router-view使用详解

    这里写目录标题 一 介绍 二 使用方法 1 实现效果 2 代码 一 介绍 router view组件作为vue最核心的路由管理组件 在项目中作为路由管理经常被使用到 vue项目最核心的App vue文件中即是通过router view进行路
  • 设置Tomcat默认访问路径

    步骤 1 打开server xml 在的上一行添加内容格式如下
  • 电脑关机一段时间后不能网络唤醒WOL

    一直以来 想实现远程开机的功能 后来经过NAT 花生壳DDNS的设置 可以通过一台常年开机的主机 来控制其他机器的开关机 但新的问题来了 就是电脑关机一段时间后不能网络唤醒WOL 按照网上教程 关闭了网卡的环保选项 在主板里也设置了WOL相
  • UE4_C++访问蓝图里的变量

    有没有碰到这样的问题 之前的同事用 连连看 实现了项目的逻辑 后续你要维护推展项目的开发 但头疼的是 你是个coder not 连连看 玩家 这时候how to do it UE4 C 访问蓝图里的变量 c 获得BP的方式 在访问蓝图变量之
  • GTest基础学习-04-第3个单元测试-测试夹具test fixture

    这篇来学习一下Gtest中更高级一些的特性test fixture 测试夹具的基本上使用 什么的场景需要使用到测试夹具呢 测试夹具是哪个宏 这篇来学习这个主题 1 什么叫test fixture 什么是测试夹具 这个概念在任何xUnit系列