Google Test(简称gtest)是一个开源的C++单元测试框架。和常见的测试工具一样,gtest提供了单体测试常见的工具和组件。比如判断各种类型的值相等,大于,小于等,管理多个测试的测试组如testsuit下辖testcase,为了方便处理初始化数据减少重复代码,提供了setup和teardown函数等。
git clone https://github.com/google/googletest.git
cd googletest
mkdir build && cd build && cmake .. && make -j4
sudo make install
sudo ldconfig
在googletest/samples
文件夹中里面存放了10个官方提供的示例代码,默认是不编译的,这里我们修改googletest/CMakeLists.txt
,将第20行的OFF改为ON。
option(gtest_build_tests "Build all of gtest's own tests." OFF)
option(gtest_build_samples "Build gtest's sample programs." ON)
option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF)
重新构建后,可以在build目录下看到googletest自带的sample都编译为了可执行文件。
root@localhost:~/gtest/build/googletest# ls
CMakeFiles Makefile generated sample1_unittest sample3_unittest sample5_unittest sample7_unittest sample9_unittest
CTestTestfile.cmake cmake_install.cmake sample10_unittest sample2_unittest sample4_unittest sample6_unittest sample8_unittest
root@localhost:~/gtest/build/googletest# ./sample1_unittest
Running main() from /root/gtest/googletest/src/gtest_main.cc
[==========] Running 6 tests from 2 test suites.
[----------] 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 suites ran. (0 ms total)
[ PASSED ] 6 tests.
在googletest的说明手册中,给出了示例代码更详细的解释:Googletest Samples,Google单元测试框架gtest之官方sample笔记1–简单用例
我们来看一个Googletest Samples1中的一段代码
TEST(FactorialTest, Zero)
{
EXPECT_EQ(1, Factorial(0));
}
这里用到了TEST宏,它有两个参数,官方的对这两个参数的解释为:[TestCaseName,TestName]
在运行的结果中我们可以看到,通过TEST宏我们启动了对FactorialTest函数的测试,名称为Zero。
[ RUN ] FactorialTest.Zero
[ OK ] FactorialTest.Zero (0 ms)
紧接出现了EXPECT_EQ(1, Factorial(0)); ,这个宏用来比较两个数字是否相等。Google还包装了一系列EXPECT_* 和ASSERT_*的宏,而EXPECT系列和ASSERT系列的区别是:
./unittest --gtest_output="xml:report.xml"
./unittest --gtest_repeat=2 --gtest_break_on_failure
表示重复运行相同的测试用例两次,如果测试失败,会自动调用调试器。
./unittest --gtest_filter=* #执行所有测试
./unittest --gtest_filter=PoissonUdpClientTest* #执行PoissonUdpClientTest开头的测试
./unittest --gtest_filter=-PoissonUdpClientTest* #不执行PoissonUdpClientTest开头的测试
gmock是谷歌推出的开源白盒测试工具,用于编写C++模拟类的框架。通过gmock可以用一些简单的宏描述想要模拟的接口并指定其期望,在测试中有效地去除外部依赖,更方便地测试模块功能。
对类里面需要打桩的函数mock,语法如下:
MOCK_METHODn(..., ...); //其中n表示参数的个数
MOCK_CONST_METHODn(..., ...); //const成员方法用这种
对mock的方法可以指定期望,包括返回值,调用次数等,使用EXPECT_CALL()宏:
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality) //可以指定调用几次
.WillOnce(action) //可以指定调用行为
.WillRepeatedly(action);
Matchers指参数匹配器,可以指定任意参数,::testing::_ 表示输入的参数为任意参数,其他参数不一一列举
Mock virtual方法如下,不需要对工程代码做修改:
// Foo.h
class Foo {
public:
virtual int FooFuncOne(int num);
};
// FooTest.cc
class MockFoo : public Foo {
public:
MOCK_METHOD1(FooFuncOne, int(int num));
};
TEST(FooTest, FooFuncOne)
{
MockFoo mockFoo;
// 指定FooFuncOne返回值为5
EXPECT_CALL(mockFoo, FooFuncOne((::testing::_)))
.WillRepeatedly((::testing::Return)(5));
}
上面mock方法主要用到了虚函数重写,但是对于非虚函数,上述写法是不能够生效的,需要有较大的改动,可以根据实际需要选择。下面贴了使用的示例:
// foo.h
class Foo {
public:
void CallSelfMethod();
void PublicMethod();
protected:
void ProtectedMethod();
private:
void PrivateMethod();
};
// 重构成模板类 foo_testable.h
template <typename T>
class FooTestable {
public:
FooTestable(T &self);
void CallSelfMethod();
void PublicMethod();
protected:
void ProtectedMethod();
private:
void PrivateMethod();
T &self;
};
// foo_test.cc
class MockFoo {
public:
MOCK_METHOD(PublicMethod, void());
MOCK_METHOD(ProtectedMethod, void());
MOCK_METHOD(PrivateMethod, void());
};
TEST(Test_MockSelfNonVirtualMethod, SelfMethod) {
MockFoo mockFoo;
FooTestable<MockFoo> fooTestable(mockFoo);
EXPECT_CALL(mockFoo, PublicMethod()).Times(1);
EXPECT_CALL(mockFoo, ProtectedMethod()).Times(1);
EXPECT_CALL(mockFoo, PrivateMethod()).Times(1);
fooTestable.CallSelfMethod();
}