GTest and ROSTest
致谢
前言
为什么要学GTest
- 开源框架,完全免费
- 用得人多,项目多,比如ROS就用这个做测试,这是我学习GTEST的直接原因
- 软件工程师入门啊!
科普
- 如果你是一名开发工程师,或者你编写的程序要用到生产环境中,那么,你不可避免的需要学习和掌握一种自动化测试框架,以确保你的程序测试充分,质量上乘。
- 其实啊,测试工具是什么并不重要,重要的是测试思想,还是在大学期间上过的课,亲身做过的项目才是真货,好吧,去考个计算机三级软件测试技术?
好的测试框架应该是(软件测试思想)
- 软件应该是独立的且可重复的,每个测试应该是一个独立的对象
- 应该有一套好的方法来组织测试,这种组织方法能够较好的反映程序代码的结构
- 测试应该是可迁移的且可复用的(平台中立)(支持多种编译器)
- 在测试失败时,要能够提供足够充分的测试信息
- 测试框架应该让开发者从琐碎的工作中解脱出来,让他们能够专注在测试内容上
- 测试应该是高效的
GTest 入门
综述
- 第一步就是:把gtest编译成一个库,并且链接到你的测试程序中
- 你的测试项目程序要引用
gtest/gtest.h
,你的gtest安装在GTEST_ROOT路径下
断言assertion
- gtest 中的断言是一些宏,assertion在测试一个函数时,可以有两种方案,即ASSERT_和EXPECT_。在失败发生时,ASSERT_这类assertion会产生fatal failure,并且会终止当前函数;而EXPECT_则只会产生nonfatal failure。
- 常用的宏有
EXPECT_EQ/NE/LT/LE/GT/GE([表达式],[表达式]) - 对于ASSERT_EQ比较两个C字符串指针,只会检查两个指针是否指向同一块区域,要想检查两个(C风格字符串)字符串内容是否相同,要使用ASSERT_STREQ,不过比较两个C++字符串的话就用ASSERT_EQ就可以了。
- 特殊的比较宏——字符串比较宏
ASSERT_STRCASEEQ(),此处CASE指不区分大小写的比较 - 字符串比较宏的特殊规则
NULL和空字符串""
是不相等的。 - 如果你想了解更多有关字符串比较的trick方法,比如在assertion中处理子字符串、前缀、后缀、正则匹配等,请进入“高级gtest指南”。
创建一个test
- 三件事
- 使用TEST()宏来定义和命名一个test函数,这个test函数不需要return任何值。
- 在这个test函数中,你可以写任何C++语句,并且使用assertion来检查。
- 这个test的结果是由assertion决定的。如果任何一个assertion失败了,或者这个test函数崩溃了,这个test则会返回fail。否则,会返回success。
- 语法
TEST(test_case_name, test_name) {
... test body ...
}
- Test Fixtures
如果你发现你所写的多个test都在操作类似的数据,那么我推荐你使用test fixture。这个特性允许你在不同的test里复用相同的配置。
机制主要是类的继承,具体请看参考教程,见文首
使用Test Fixtures时的宏
TEST_F(test_case_name, test_name) {
... test body ...
}// test_case_name 必须是定义的test fixture类的名称
运行测试
如果要触发运行,请执行RUN_ALL_TESTS()宏,如果所有的test都测试通过,它会返回0,否则会返回1。
- 注意
你bixu在你的main函数中return这个值。
编写测试的main函数
- 参考如下模板
#include "this/package/foo.h"
#include "gtest/gtest.h"
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body is empty.
FooTest() {
// You can do set-up work for each test here.
}
Virtual ~FooTest() {
// 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:
virtual void SetUp() {
// Code here will be called immediately after the constructor
}
virtual void TearDown() {
// Code here will be called immediately after each test
}
// Object declared here can be used by all tests in the test case for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const string input_filepath = "this/package/testdata/myinputfile.dat";
const string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Execises the Xyz feature of Foo.
}
} // namespace
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}