转载自:https://blog.csdn.net/jcjc918/article/details/52029455
https://www.cnblogs.com/Jessica-jie/p/6705067.html
[gtest快速入门]
gtest 提供了一套优秀的 C++ 单元测试解决方案,简单易用,功能完善,非常适合在项目中使用以保证代码质量。
安装
官方传送门:googletest
现在官方已经把 gtest 和 gmock 一起维护,所以这个 git 仓库还包含了 gmock。
这里建议安装 gtest 1.7 release 版本(该安装方法对 1.8 不适用):
➜ ~ wget https://github.com/google/googletest/archive/release-1.7.0.tar.gz
➜ ~ tar xf release-1.7.0.tar.gz
➜ ~ cd googletest-release-1.7.0
➜ googletest-release-1.7.0 cmake -DBUILD_SHARED_LIBS=ON .
➜ googletest-release-1.7.0 make
➜ googletest-release-1.7.0 sudo cp -a include/gtest /usr/include
➜ googletest-release-1.7.0 sudo cp -a libgtest_main.so libgtest.so /usr/lib/
这样就 OK 了,可以用 sudo ldconfig -v | grep gtest 检查,看到下面就 OK 了:
libgtest.so -> libgtest.so
libgtest_main.so -> libgtest_main.so
使用
官方 WIKI:Gtest
断言
gtest 使用一系列断言的宏来检查值是否符合预期,主要分为两类:ASSERT 和 EXPECT。区别在于 ASSERT 不通过的时候会认为是一个 fatal 的错误,退出当前函数(只是函数)。而 EXPECT 失败的话会继续运行当前函数,所以对于函数内几个失败可以同时报告出来。通常我们用 EXPECT 级别的断言就好,除非你认为当前检查点失败后函数的后续检查没有意义。
基础的断言
Fatal assertion Nonfatal assertion Verifies
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false
数值比较
Fatal assertion Nonfatal assertion Verifies
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(val1,val2); EXPECT_GT(val1,val2); val1 > val2
ASSERT_GE(val1,val2); EXPECT_GE(val1,val2); val1 >= val2
字符串比较
Fatal assertion Nonfatal assertion Verifies
ASSERT_STREQ(str1,str2); EXPECT_STREQ(str1,_str_2); 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(str1,str2); EXPECT_STRCASEEQ(str1,str2); 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
Samples
我们安装时下载的代码就包含了 10 个例子,可以直接在根目录下执行 make 并运行。进入 samples 文件夹,阅读每份功能代码和对应的测试文件,可以帮助我们较快入门。我们下面看一下简单的例子。
sample1
#include <limits.h>
#include "sample1.h"
#include "gtest/gtest.h"
// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {
// This test is named "Negative", and belongs to the "FactorialTest"
// test case.
EXPECT_EQ(1, Factorial(-5));
EXPECT_EQ(1, Factorial(-1));
EXPECT_GT(Factorial(-10), 0);
}
...
TEST(IsPrimeTest, Positive) {
EXPECT_FALSE(IsPrime(4));
EXPECT_TRUE(IsPrime(5));
EXPECT_FALSE(IsPrime(6));
EXPECT_TRUE(IsPrime(23));
}
sample1 演示了简单测试用例的编写,主要使用了 TEST() 宏。这个宏的使用类似于:
TEST(test_case_name, test_name) {
... test body ...
一个 test_case_name 对应一个函数的测试用例,test_name 可以对应这个测试用例下的某个场景的测试集。这两个名字可以任意取,但应该是有意义的,而且不能包含下划线 _ 。
sample1 运行结果如下:
如果出错的话会提醒我们哪个用例错误,哪个检查点不通过,以及对应代码位置,非常棒。
sample3
sample3 用来演示一个测试夹具的使用。前面我们每个测试用例每个测试集间都是完全独立的,使用的数据也互不干扰。但如果我们使用的测试集需要使用一些相似的数据呢?或者有些相似的检查方法?这时就需要用到测试夹具了。
#include "sample3-inl.h"
#include "gtest/gtest.h"
// To use a test fixture, derive a class from testing::Test.
class QueueTest : public testing::Test {
protected: // You should make the members protected s.t. they can be
// accessed from sub-classes.
// virtual void SetUp() will be called before each test is run. You
// should define it if you need to initialize the varaibles.
// Otherwise, this can be skipped.
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() will be called after each test is run.
// You should define it if there is cleanup work to do. Otherwise,
// you don't have to provide it.
//
// virtual void TearDown() {
// }
// A helper function that some test uses.
static int Double(int n) {
return 2*n;
}
// A helper function for testing Queue::Map().
void MapTester(const Queue<int> * q) {
// Creates a new queue, where each element is twice as big as the
// corresponding one in q.
const Queue<int> * const new_q = q->Map(Double);
// Verifies that the new queue has the same size as q.
ASSERT_EQ(q->Size(), new_q->Size());
// Verifies the relationship between the elements of the two queues.
for ( const QueueNode<int> * n1 = q->Head(), * n2 = new_q->Head();
n1 != NULL; n1 = n1->next(), n2 = n2->next() ) {
EXPECT_EQ(2 * n1->element(), n2->element());
}
delete new_q;
}
// Declares the variables your tests want to use.
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
// When you have a test fixture, you define a test using TEST_F
// instead of TEST.
// Tests the default c'tor.
TEST_F(QueueTest, DefaultConstructor) {
// You can access data in the test fixture here.
EXPECT_EQ(0u, q0_.Size());
}
// Tests Dequeue().
TEST_F(QueueTest, Dequeue) {
int * n = q0_.Dequeue();
EXPECT_TRUE(n == NULL);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0u, q1_.Size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1u, q2_.Size());
delete n;
}
// Tests the Queue::Map() function.
TEST_F(QueueTest, Map) {
MapTester(&q0_);
MapTester(&q1_);
MapTester(&q2_);
}
可以看到我们首先需要从 testing::Test 来派生一个自己的测试类QueueTest,在这个类里你可以定义一些必要的成员变量或者辅助函数,还可以定义 SetUp 和 TearDown 两个虚函数,来指定每个测试集运行前和运行后应该做什么。后面测试用例的每个测试集应该使用 TEST_F 宏,第一个参数是我们定义的类名,第二个是测试集的名称。
对于每个 TEST_F 函数,对应的执行过程如下:
1. 创建测试夹具类(也就是说每个 TEST_F 都有一个运行时创建的夹具)。
2. 用 SetUp 函数初始化。
3. 运行测试集。
4. 调用 TearDown 进行清理。
5. delete 掉测试夹具。
其他
gtest 还提供了其他更灵活也更复杂的测试方法,可以参考 sample5 之后的例子。这里限于篇幅就不介绍了,而且就我而言即使在生产环境也不需要用到这么复杂的测试方法。
The End
最后的最后,希望大家把 gtest 用起来,单元测试对代码质量的保证作用真是非常大~
————————————————
版权声明:本文为CSDN博主「一线涯」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jcjc918/article/details/52029455
Linux下Google Test (GTest)测试环境搭建步骤
1.下载GTEST
下载链接为:https://code.google.com/p/googletest/downloads/list
目前GTEST的最新版本为gtest-1.7.0.zip,因此我们在本文中将以这个版本作为例子讲解。
2.认识文件夹
下载并解压之后,就可以看到gooletest(gtest-1.7.0)文件夹了,里面的内容如下图所示:
这么多文件看起来很麻烦。其实,GTEST提供了对于多个不同平台的支持,例如msvc文件夹是用在微软Visual Studio中,xcode文件夹是用于Mac Xcode,codegrear文件夹是用于Borland C++ Builder,在Linux环境中,我们用的内容就是make文件夹了。
3.清除不需要的文件
前一步中我们已经讲到,很多文件是为了支持不同平台的,为了保持程序的简洁,避免混淆试听,我们在这一步把所有不需要的文件全部删除,只保留我们需要的。
只剩下了四个文件夹,看上去好多了。其实打开make文件夹,你会发现里面只有一个Makefile文件。查看Makefile文件内容,得知这是系统给出的编译samples文件夹中的第一个sample的命令。但是打开sample文件夹,又看到里面一大坨源文件。在本入门教程中,我们先不考虑那些复杂的例子。因此,打开samples文件夹,开始删文件,删到只剩下如图所示的三个文件为止。
4.改写Makefile文件
到make文件夹下,通过命令行执行 $ make && ./sample1_unittest 命令,可以看到测试的执行结果。
[email protected]:~/gtest/googletest/make$ make && ./sample1_unittest g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1.cc g++ -isystem ../include -g -Wall -Wextra -pthread -c ../samples/sample1_unittest.cc g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c \ ../src/gtest-all.cc g++ -isystem ../include -I.. -g -Wall -Wextra -pthread -c \ ../src/gtest_main.cc ar rv gtest_main.a gtest-all.o gtest_main.o ar: creating gtest_main.a a - gtest-all.o a - gtest_main.o g++ -isystem ../include -g -Wall -Wextra -pthread -lpthread sample1.o sample1_unittest.o gtest_main.a -o sample1_unittest Running main() from gtest_main.cc [==========] Running 6 tests from 2 test cases. [----------] Global test environment set-up. [----------] 3 tests from FactorialTest [ RUN ] FactorialTest.Negative [ OK ] FactorialTest.Negative (0 ms) [ RUN ] FactorialTest.Zero [ OK ] FactorialTest.Zero (0 ms) [ RUN ] FactorialTest.Positive [ OK ] FactorialTest.Positive (0 ms) [----------] 3 tests from FactorialTest (0 ms total) [----------] 3 tests from IsPrimeTest [ RUN ] IsPrimeTest.Negative [ OK ] IsPrimeTest.Negative (0 ms) [ RUN ] IsPrimeTest.Trivial [ OK ] IsPrimeTest.Trivial (0 ms) [ RUN ] IsPrimeTest.Positive [ OK ] IsPrimeTest.Positive (0 ms) [----------] 3 tests from IsPrimeTest (0 ms total) [----------] Global test environment tear-down [==========] 6 tests from 2 test cases ran. (0 ms total) [ PASSED ] 6 tests.
不过如果打开Makefile查看一下,就会发现这个makefile只适用于编译sample1,如果我再增加一个被测的源文件呢?又要重新写makefile,太麻烦了。于是,在这一步,我们改写一下Makefile。
上一步我们讲到,现在只剩下4个文件夹(include,make,samples,src),既然make里面的唯一一个文件也要被改写,那也没必要留这个文件夹了。于是,你要做的第一件事情就是,把make文件夹,连同里面的Makefile文件全部删除……然后,进入samples文件夹,自己创建一个文件,名为Makefile,如图所示
然后,打开Makefile文件,写入以下内容。这个新的Makefile是由刚才被我们删除的Makefile改写而来的,如果你好奇的话可以比较一下它们之间的差别,里面涉及到一些makefile的语法和函数,如果不熟的话,你可能需要花费几分钟查一下资料去了解他们。
注意下图中改写的Makefile第32行,我们编译的是后缀名为cpp的文件,而原来给的例子却以cc结尾。因此,你还要做一件事情,就是把sample1.cc的文件名改为sample1.cpp,把sample1_unittest.cc的文件名改为sample1_unittest.cpp,就大功告成了。
GTEST_DIR = ..
USER_DIR = .
CPPFLAGS += -isystem $(GTEST_DIR)/include
CXXFLAGS += -g -Wall -Wextra -pthread
TESTS = run_test
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
FILES =$(foreach d,$(USER_DIR),$(wildcard $(d)/*.cpp))
OBJS =$(patsubst %.cpp,%.o,$(FILES))
all : $(TESTS)
clean :
rm -f $(TESTS) gtest_main.a *.o
.PHONY :clean
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) [email protected] $^
%.o :%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o [email protected]
$(TESTS) : $(OBJS) gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o [email protected]
现在我们的文件夹有三个(include,src,samples),我们自己被测的程序放在samples文件夹中。这个文件夹的名字看着也比较不爽,你可以把它改为mycode或者testcode,然后GTEST根目录的文件夹名称gtest-1.7.0也可以改为mygtest之类,。如图所示:
现在,进入命令行进行编译执行操作: $ make && ./run_test,就可以看到结果了,如图所示:
6.添加自己的测试函数
参考http://www.linuxidc.com/Linux/2015-05/116894.htm
[完毕]