Gtest入门2 Gtest之TEST宏的用法

1. TestCase的介绍

本章节主要介绍在使用Gtest单元测试的常用宏的用法及说明。其目的达到如何使用Gtest即可不做深入研究其运行原理。
Gtest提供了若干个case方法进行测试不同的用例。主要常见的有TEST/TEST_F及TEST_P宏的使用。
在每个TestCase中可以通过断言([断言类型介绍])提供的方法进行控制检查程序的预期走向是否是期望的结果,从而以此来判定程序的正确性。
在同一份TestCase中不能同时出现TEST和TEST_F两者进行混用;
其次TEST_F比TEST强的地方是会通过继承::testing::Test生成一个新类,而且这是必须的。在新类中可以通过void SetUp();和void TearDown();进行创建和清除相关的资源数据;

2. TEST宏

TEST宏的作用是创建一个简单测试,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言([断言类型介绍])来进行检查。

TEST语法定义:
TEST(test_case_name, test_name)
  • test_case_name第一个参数是测试用例名,通常是取测试函数名或者测试类名
  • test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
  • 当测试完成后显示的测试结果将以"测试用例名.测试名"的形式给出

如下程序一个测试share_ptr的引用计数:

// SharedUnique.cpp
#include <iostream>
#include <memory>
#include <gtest/gtest.h>

// A custom make_unique templete class
#include <Memory.h>

using namespace sampleCXX::common;

class Base {
public:
	Base(std::string name):m_name{name} {
		std::cout << "name: " << m_name << std::endl;
	}

	std::string getName() {
		return m_name;
	}
	~Base() {
		
		std::cout << "destory base" << std::endl;
	}
private:
	std::string m_name;
};

void getNameFunc(std::shared_ptr<Base> base) {
	std::cout << __func__ << " : usercount: " << base.use_count() << std::endl;
	std::cout << __func__ << " : name: " << base->getName() << std::endl;
	// EXPECT_EQ(2, base.use_count());
}

TEST(Base, createInstance) {
	std::unique_ptr<Base> instance = make_unique<Base>("SvenBaseUnique");
	// 测试创建的instance实例是否不为nullptr
	EXPECT_NE(instance, nullptr);
	instance.reset();
	// 测试instance实例是否为nullptr
	EXPECT_EQ(instance, nullptr);
}

TEST(Base, getName) {
	std::unique_ptr<Base> instance = make_unique<Base>("BaseUnique");
	EXPECT_NE(instance, nullptr);
	auto name = instance->getName();
	// 测试获取的name值是否和被给的值相等
	EXPECT_STREQ(name.c_str(), "BaseUnique");
	instance.reset();
	EXPECT_EQ(instance, nullptr);
}

TEST(Base, shared_ptr) {
	std::shared_ptr<Base> instance = std::make_shared<Base>("BaseShared");
	EXPECT_NE(instance, nullptr);
	std::cout << "shared_ptr.use_count: " << instance.use_count() << std::endl;
	// 测试instance引用次数是否为1
	EXPECT_EQ(1, instance.use_count());
	getNameFunc(instance);
	EXPECT_EQ(1, instance.use_count());
}

TEST(Base, unique_ptr) {
	std::unique_ptr<Base> instance = make_unique<Base>("BaseUnique");
	EXPECT_NE(instance, nullptr);
	getNameFunc(std::move(instance));
	EXPECT_EQ(instance, nullptr);
}

以上关于EXPECT_*断言宏请查看断言小结的解释【[断言类型介绍]
执行结果:
在这里插入图片描述
测试结果都是"测试用例名.测试名"的形式给出。

以上代码可以执行下载运行:shared_unique

3. TEST_F宏

TEST_F主要是进行多样测试,就是多种不同情况的测试TestCase中都会使用相同一份的测试数据的时候将会才用它。
即用相同的数据测试不同的行为,如果采用TEST宏进行测试那么将会为不同的测试case创建一份数据。TEST_F宏将会共用一份避免重复拷贝共具灵活性。

语法定义为:
TEST_F(test_case_name, test_name);
  • test_case_name第一个参数是测试用例名,必须取类名。这个和TEST宏不同
  • test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
  • 使用TEST_F时必须继承::testing::Test类。并且该类提供了两个接口void SetUp(); void TearDown();
    void SetUp()函数,为测试准备对象.
    void TearDown()函数 为测试后销毁对象资源。

如下程序测试一个Base类的两个方法,它们都共用相同的数据(Base类对象):
程序通过BaseTest类创建一个共用的数据资源,这个在测试时将无需为没有测试用例单独创建Base对象。

#include <iostream>
#include <memory>
#include <gtest/gtest.h>

#include <Memory.h>

using namespace sampleCXX::common;

class Base {
public:
	Base(std::string name):m_name{name} {
		std::cout << "Create constructor name: " << m_name << std::endl;
	}

	std::string getName() {
		return m_name;
	}

	void setName(const std::string &name) {
		m_name = std::string(name);
	}

	~Base() {
		
		std::cout << "Destory base" << std::endl;
	}
private:
	std::string m_name;
};


class BaseTest : public ::testing::Test {
protected:
	// 为测试准备数据对象
	void SetUp() override {
		m_base = std::make_shared<Base>("SvenBaseTest");
	}
	// 清除资源
	void TearDown() override {
		m_base.reset();
	}

	std::shared_ptr<Base> m_base;
};

TEST_F(BaseTest, testCreateInstance) {
	std::unique_ptr<Base> instance = make_unique<Base>("SvenBaseUnique");
	EXPECT_NE(instance, nullptr);
	instance.reset();
	EXPECT_EQ(instance, nullptr);
}

TEST_F(BaseTest, testGetName) {
	auto name = m_base->getName();
	EXPECT_STREQ(name.c_str(), "SvenBaseTest");
}

TEST_F(BaseTest, testSetName) {
	m_base->setName("NewSvenBase");
	auto name = m_base->getName();
	EXPECT_STREQ(name.c_str(), "NewSvenBase");
}

执行结果:
在这里插入图片描述
以上代码可在这下载并运行:shared_unique

4. TEST_P宏

// TODO

5. EXPECT_*和ASSERT_*的宏介绍

5.1.gtest之断言

要测试一个类或函数,我们需要对其行为做出断言。当一个断言失败时,Google Test会在屏幕上输出该代码所在的源文件及其所在的位置行号,以及错误信息。也可以在编写断言时,提供一个自定义的错误信息,这个信息在失败时会被附加在Google Test的错误信息之后。

断言常常成对出现,它们都测试同一个类或者函数,但对当前功能有着不同的效果。ASSERT_*版本的断言失败时会产生致命失败,并结束当前函数。EXPECT_*版本的断言产生非致命失败,而不会中止当前函数。通常更推荐使用EXPECT_*断言,因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败,就没有必要继续往下执行的测试时,你应该使用ASSERT_*断言。 因为失败的ASSERT_*断言会立刻从当前的函数返回,可能会跳过其后的一些的清洁代码,这样也许会导致空间泄漏。

gtest中断言的宏可以分为两类:一类是ASSERT宏,另一类就是EXPECT宏了。
1、ASSERT_*系列:如果当前点检测失败则退出当前函数
2、EXPECT_*系列:如果当前点检测失败则继续往下执行

根据以上就很容易明白什么情况选择ASSERT_; 什么情况下应该选择EXPECT_;

5.2. gtest断言分类

5.2.1 Boolean断言类型

致命断言非致命断言结果
ASSERT_TRUE(condition)EXPECT_TRUE(condition)condition 为true
ASSERT_FALSE(condition)EXPECT_FALSE(condition)condition 为false

5.2.2 二元值断言类型

比较两个值的大小。

致命断言非致命断言判断结果
ASSERT_EQ(val1, val2)EXPECT_EQ(val1, val2)val1 = val2
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()EXPECT_GT()val1 > val2
ASSERT_GE(val1, val2)EXPECT_GE(val1, val2)val1 >= val2

5.2.3 字符串断言类型

比较两个字符串。

致命断言非致命断言结果
ASSERT_STREQ(val1, val2)EXPECT_STREQ(val1, val2)val1 == val2
ASSERT_STRNE()EXPECT_STRNE()val1 != val2
ASSERT_STRCASEEQ()EXPECT_STRCASEEQ()忽略大小写val1 == val2
ASSERT_STRCASENE()EXPECT_STRCASENE()忽略大小写 val1 != val2

6. 设置期望

EXPECT_CALL的用法是在gmock中的成员。如果需要mock进行模拟类的创建请查看下一章gmock的用法;

7. 调用小记

摘录:
TEST()并TEST_F()使用googletest隐式注册他们的测试。因此,与许多其他C ++测试框架不同,您不必重新列出所有已定义的测试以便运行它们。

在定义测试之后,您可以使用RUN_ALL_TESTS()它来运行它们,0如果所有测试都成功,1则返回它们。请注意,在链接单元中 RUN_ALL_TESTS()运行所有测试 - 它们可以来自不同的测试用例,甚至是不同的源文件。

调用时,RUN_ALL_TESTS()宏:

  • 保存所有googletest标志的状态
    为第一次测试创建测试夹具对象。

  • 通过初始化它SetUp()。

  • 在夹具对象上运行测试。

  • 通过清理夹具TearDown()。

  • 删除夹具。

  • 恢复所有googletest标志的状态

  • 重复上述步骤进行下一次测试,直到所有测试都运行完毕。

如果发生致命故障,将跳过后续步骤。

重要提示:您不能忽略返回值RUN_ALL_TESTS(),否则您将收到编译器错误。此设计的基本原理是自动化测试服务根据其退出代码确定测试是否已通过,而不是根据其stdout / stderr输出; 因此你的main()函数必须返回值RUN_ALL_TESTS()。
此外,你应该RUN_ALL_TESTS()只打一次电话。多次调用它会与某些高级googletest功能(例如线程安全死亡测试)冲突,因此不受支持。

其实Gtest相比Gmock的使用是简单的多了,主要合理的使用以上断言就能为自己的程序写出一个自动化的测试流程;

下一章节将介绍比Gtest更复杂和灵活的Gmock的入门使用。

  • 11
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值