googletest是由谷歌的测试技术团队开发的测试框架,使用c++实现,具有跨平台等特性。

好的测试框架

引用谷歌给出的文档,好的测试应当具备以下特征:

  • 测试应该是独立的和可重复的。调试一个由于其他测试而成功或失败的测试是一件痛苦的事情。googletest通过在不同的对象上运行测试来隔离测试。当测试失败时,googletest允许您单独运行它以快速调试。
  • 测试应该很好地“组织”,并反映出测试代码的结构。googletest将相关测试分组到可以共享数据和子例程的测试套件中。这种通用模式很容易识别,并使测试易于维护。当人们切换项目并开始在新的代码库上工作时,这种一致性尤其有用。
  • 测试应该是“可移植的”和“可重用的”。谷歌有许多与平台无关的代码;它的测试也应该是平台中立的。googletest可以在不同的操作系统上工作,使用不同的编译器,所以googletest测试可以在多种配置下工作。
  • 当测试失败时,他们应该提供尽可能多的关于问题的“信息”。谷歌测试不会在第一次测试失败时停止。相反,它只停止当前的测试并继续下一个测试。还可以设置报告非致命失败的测试,在此之后当前测试将继续进行。因此,您可以在一个运行-编辑-编译周期中检测和修复多个错误。总结一下,测试失败时尽可能多地输出错误信息。通过断言,一次测试发现或修复多个问题。
  • 测试框架应该将测试编写者从日常琐事中解放出来,让他们专注于测试“内容”。Googletest自动跟踪所有定义的测试,并且不要求用户为了运行它们而枚举它们。也就是说,开发人员只需要关注测试本身,自动跟踪所有定义测试而不要枚举它们。
  • 测试应该是“快速的”。使用googletest,您可以在测试之间重用共享资源,并且只需要为设置/拆除支付一次费用,而无需使测试彼此依赖。一句话,测试要高效。

再给一张图

基本操作

下载安装

github下载

git clone https://github.com/google/googletest.git

或者直接下载压缩包

wget https://github.com/google/googletest/releases/tag/release-1.11.0

编译安装

# 解压后进入目录
cd googletest
cmake CMakeLists.txt
make
sudo make install

使用方法

测试使用在编译之后,实际执行之前。

# 当不想写 main 函数的时候,可以直接引入 libgtest_main.a
g++ sample.cc -o sample -lgtest -lgtest_main -lpthread
g++ sample.cc -o sample -lgmock -lgmock_main -lpthread# 如果自己写了main函数,就不用引入 libgtest_main.a
g++ sample.cc -o sample -lgtest -lpthread

编译解决语法问题,测试解决逻辑问题。

重要文件

googletest:

  • gtest.h:googletest用来单元测试的头文件
  • libgtest.a:静态测试的接口都在这个静态库中实现
  • libgtest_main.a:里面提供了一个main函数以及初始化libgtest.a的代码

这里可能会有疑问,这里提前写好的main函数怎么调用到我们现写的测试案例的呢?这是因为测试案例都会通过TEST()宏加入到一个全局vector中,main()函数会调用RUN_ALL_TESTS(),这就可以把所有加入到这个vector中的测试案例都执行了。
贴一下TEST()和RUN_ALL_TESTS()的核心代码

void TestCase::AddTestInfo(TestInfo * test_info) {                                                                            test_info_list_.push_back(test_info);                                                                                       test_indices_.push_back(static_cast<int>(test_indices_.size()));                                                            }
for (int test_index = 0; test_index < total_test_case_count();test_index++) {                                                                                                       GetMutableTestCase(test_index)->Run(); //逐个运行测试用例,执行后面的TestBody()                                                                                  }

googlemock:与googletest类似,注意googlemock依赖googletest

  • gmock/gmock.h:都不解释了
  • libgmock.a
  • libgmock_main.a

基本概念

给一个关系图

一个项目中通常只有一个单元测试,一个单元测试中包含多个测试套件,一个测试套件中包含多个测试案例,一个测试案例中有多个断言。

断言

断言其实之前接触过:assert()。googletest要比这个功能多一些。
断言成对出现,它们测试相同的东西,但对当前函数有不同的影响。 ASSERT_* 版本在失败时产生致命失败,并中止当前函数。 EXPECT_* 版本生成非致命失败,它不会中止当前函数。通常首选EXPECT_* ,因为它们允许在测试中报告一个以上的失败。但是,如果在有问题的断言失败时继续没有意义,则应该使用 ASSERT_* 。也就是说,使用ASSERT,错误就退出;使用EXPECT,错误了没有影响,继续执行。

EXPECT_TRUE( condition );
ASSERT_TRUE( condition );
EXPECT_FALSE( condition );
ASSERT_FALSE( condition );//二元比较
//等于
EXPECT_EQ( val1 , val2 );
ASSERT_EQ( val1 , val2 );//不等于,注意比较空指针的时候,使用EXPECT_NE( ptr , nullptr) 而不是 EXPECT_NE( ptr , NULL)
EXPECT_NE( val1 , val2 );
ASSERT_NE( val1 , val2 );//小于
EXPECT_LT( val1 , val2 );
ASSERT_LT( val1 , val2 );//小于等于
EXPECT_LE( val1 , val2 );
ASSERT_LE( val1 , val2 );//大于
EXPECT_GT( val1 , val2 );
ASSERT_GT( val1 , val2 );//大于等于
EXPECT_GE( val1 , val2 );
ASSERT_GE( val1 , val2 );//谓词断言,能比 EXPECT_TRUE 提供更详细的错误消息
EXPECT_PRED1( pred , val1 );
EXPECT_PRED2( pred , val1 , val2 );
EXPECT_PRED3( pred , val1 , val2 , val3 );
EXPECT_PRED4( pred , val1 , val2 , val3 , val4 );
EXPECT_PRED5( pred , val1 , val2 , val3 , val4 , val5 );
ASSERT_PRED1( pred , val1 );
ASSERT_PRED2( pred , val1 , val2 );
ASSERT_PRED3( pred , val1 , val2 , val3 );
ASSERT_PRED4( pred , val1 , val2 , val3 , val4 );
ASSERT_PRED5( pred , val1 , val2 , val3 , val4 , val5 );

举例子

//TEST()是一个测试案例,第一个参数是测试套件的名字,第二个参数是测试案例的名字
TEST(FactorialTest, Negative) {// This test is named "Negative", and belongs to the "FactorialTest" test caseEXPECT_EQ(1, Factorial(-5));EXPECT_EQ(1, Factorial(-1));EXPECT_GT(Factorial(-10), 0);
}TEST(IsPrimeTest, Negative) {// This test belongs to the IsPrimeTest test case.EXPECT_FALSE(IsPrime(-1));EXPECT_FALSE(IsPrime(-2));EXPECT_FALSE(IsPrime(INT_MIN));
}
// Returns true if m and n have no common divisors except 1.
bool MutuallyPrime(int m, int n) { ... }
...
const int a = 3;
const int b = 4;
const int c = 10;
...
EXPECT_PRED2(MutuallyPrime, a, b); // Succeeds
EXPECT_PRED2(MutuallyPrime, b, c); // Fails

所有断言宏都支持输出流,也就是当出现错误的时候,我们可以通过流输出更详细的信息;注意编码问题,经流输出的信息会自动转换为 UTF-8

EXPECT_TRUE(my_condition) << "My condition is not true";

这样会在终端打印出来,可以用来输出更详细的测试信息。

googletest

主要是

#define TEST(test_suite_name,test_name)

类的测试

类的测试逻辑要按照默认构造、传参构造、拷贝构造、具体方法的顺序来测试。这样的话,其他人来看代码的话,就算只看测试代码,也能清楚类的具体实现。也就是说,这个测试案例起到了文档的功能。

//里面的方法实现就略了
class MyString {private:const char* c_string_;const MyString& operator=(const MyString& rhs);public:// Clones a 0-terminated C string, allocating memory using new.static const char* CloneCString(const char* a_c_string);//// C'tors// The default c'tor constructs a NULL string.MyString() : c_string_(nullptr) {}// Constructs a MyString by cloning a 0-terminated C string.explicit MyString(const char* a_c_string) : c_string_(nullptr) {Set(a_c_string);}// Copy c'torMyString(const MyString& string) : c_string_(nullptr) {Set(string.c_string_);}//// D'tor.  MyString is intended to be a final class, so the d'tor// doesn't need to be virtual.~MyString() { delete[] c_string_; }// Gets the 0-terminated C string this MyString object represents.const char* c_string() const { return c_string_; }size_t Length() const { return c_string_ == nullptr ? 0 : strlen(c_string_); }// Sets the 0-terminated C string this MyString object represents.void Set(const char* c_string);
};// Tests the default c'tor.
TEST(MyString, DefaultConstructor) {const MyString s;// Asserts that s.c_string() returns NULL.//// <TechnicalDetails>//// If we write NULL instead of////   static_cast<const char *>(NULL)//// in this assertion, it will generate a warning on gcc 3.4.  The// reason is that EXPECT_EQ needs to know the types of its// arguments in order to print them when it fails.  Since NULL is// #defined as 0, the compiler will use the formatter function for// int to print it.  However, gcc thinks that NULL should be used as// a pointer, not an int, and therefore complains.//// The root of the problem is C++'s lack of distinction between the// integer number 0 and the null pointer constant.  Unfortunately,// we have to live with this fact.//// </TechnicalDetails>EXPECT_STREQ(nullptr, s.c_string());EXPECT_EQ(0u, s.Length());
}const char kHelloString[] = "Hello, world!";// Tests the c'tor that accepts a C string.
TEST(MyString, ConstructorFromCString) {const MyString s(kHelloString);EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1,s.Length());
}// Tests the copy c'tor.
TEST(MyString, CopyConstructor) {const MyString s1(kHelloString);const MyString s2 = s1;EXPECT_EQ(0, strcmp(s2.c_string(), kHelloString));
}// Tests the Set method.
TEST(MyString, Set) {MyString s;s.Set(kHelloString);EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));// Set should work when the input pointer is the same as the one// already in the MyString object.s.Set(s.c_string());EXPECT_EQ(0, strcmp(s.c_string(), kHelloString));// Can we set the MyString to NULL?s.Set(nullptr);EXPECT_STREQ(nullptr, s.c_string());
}

test fixture测试夹具

在实际测试的过程中,类与类的依赖关系比较紧密,也可能会有多个类来工作。这时就需要包装一个测试对象,这个测试对象就叫测试夹具。
如果希望一些变量在一个测试套件的多个测试案例中都可以使用,就用测试夹具。

// 定义类型,继承自 testing::Test
class TestFixtureSmpl : public testing::Test {protected:void SetUp() {} // 测试夹具测试前调用的函数 -- 做初始化的工作void TearDown() {} // 测试夹具测试后调用的函数 -- 做清理的工作
};// 需要在 TEST_F 中书写测试用例
#define TEST_F(test_fixture,test_name)// 如果需要复用测试夹具,只需要继承自 TestFixtureSmpl
class TestFixtureSmpl_v2 : public TestFixtureSmpl {};

举例子

// To use a test fixture, derive a class from testing::Test.
class QueueTestSmpl3 : 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 variables.// Otherwise, this can be skipped.// override表示编译期间覆盖函数void SetUp() override {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 != nullptr; 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(QueueTestSmpl3, DefaultConstructor) {// You can access data in the test fixture here.EXPECT_EQ(0u, q0_.Size());
}// Tests 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;
}// Tests the Queue::Map() function.
TEST_F(QueueTestSmpl3, Map) {MapTester(&q0_);MapTester(&q1_);MapTester(&q2_);
}

类型参数化

有时候相同的接口,有多个实现,依赖测试夹具。下面是复用测试代码流程

using testing::Test;
using testing::Types;// 先申明测试夹具
template <class T>
class TestFixtureSmpl : public testing::Test {protected:void SetUp() {} // 测试夹具测试前调用的函数 -- 做初始化的工作void TearDown() {} // 测试夹具测试后调用的函数 -- 做清理的工作
};// 枚举测试类型
typedef Types<Class1, Class2, class3> Implementations;
// #define TYPED_TEST_SUITE(CaseName,Types,__VA_ARGS__...)
// 注意 casename 一定要与测试夹具的名字一致
TYPED_TEST_SUITE(TestFixtureSmpl, Implementations);// #define TYPED_TEST(CaseName,TestName)
// 开始测试, CaseName 要与 TYPED_TEST_SUITE 一致
TYPED_TEST(TestFixtureSmpl, TestName);

例子

template <class T>
class PrimeTableTest : public testing::Test {protected:// The ctor calls the factory function to create a prime table// implemented by T.PrimeTableTest() : table_(CreatePrimeTable<T>()) {}~PrimeTableTest() override { delete table_; }// Note that we test an implementation via the base interface// instead of the actual implementation class.  This is important// for keeping the tests close to the real world scenario, where the// implementation is invoked via the base interface.  It avoids// got-yas where the implementation class has a method that shadows// a method with the same name (but slightly different argument// types) in the base interface, for example.PrimeTable* const table_;
};using testing::Types;// Google Test offers two ways for reusing tests for different types.
// The first is called "typed tests".  You should use it if you
// already know *all* the types you are gonna exercise when you write
// the tests.// To write a typed test case, first use
//
//   TYPED_TEST_SUITE(TestCaseName, TypeList);
//
// to declare it and specify the type parameters.  As with TEST_F,
// TestCaseName must match the test fixture name.// The list of types we want to test.
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;TYPED_TEST_SUITE(PrimeTableTest, Implementations);// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
// similar to TEST_F.
TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) {// Inside the test body, you can refer to the type parameter by// TypeParam, and refer to the fixture class by TestFixture.  We// don't need them in this example.// Since we are in the template world, C++ requires explicitly// writing 'this->' when referring to members of the fixture class.// This is something you have to learn to live with.EXPECT_FALSE(this->table_->IsPrime(-5));EXPECT_FALSE(this->table_->IsPrime(0));EXPECT_FALSE(this->table_->IsPrime(1));EXPECT_FALSE(this->table_->IsPrime(4));EXPECT_FALSE(this->table_->IsPrime(6));EXPECT_FALSE(this->table_->IsPrime(100));
}TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) {EXPECT_TRUE(this->table_->IsPrime(2));EXPECT_TRUE(this->table_->IsPrime(3));EXPECT_TRUE(this->table_->IsPrime(5));EXPECT_TRUE(this->table_->IsPrime(7));EXPECT_TRUE(this->table_->IsPrime(11));EXPECT_TRUE(this->table_->IsPrime(131));
}TYPED_TEST(PrimeTableTest, CanGetNextPrime) {EXPECT_EQ(2, this->table_->GetNextPrime(0));EXPECT_EQ(3, this->table_->GetNextPrime(2));EXPECT_EQ(5, this->table_->GetNextPrime(3));EXPECT_EQ(7, this->table_->GetNextPrime(5));EXPECT_EQ(11, this->table_->GetNextPrime(7));EXPECT_EQ(131, this->table_->GetNextPrime(128));
}

有时候你写了某个接口,期望其他人实现它,你可能想写一系列测试,确保其他人的实现满足你的测试

// 首先声明测试类型参数化(_P 是 parameterized or pattern)
// #define TYPED_TEST_SUITE_P(SuiteName)
TYPED_TEST_SUITE_P(TestFixtureSmpl);// 书写测试, suiteName 与上面一致
// #define TYPED_TEST_P(SuiteName,TestName)
TYPED_TEST_P(TestFixtureSmpl,TestName)// 枚举所有测试
// #define REGISTER_TYPED_TEST_SUITE_P(SuiteName,__VA_ARGS__...)
REGISTER_TYPED_TEST_SUITE_P(TestFixtureSmpl, TestName1,TestName2,...)// 上面定义的是抽象测试类型
// 其他人实现功能后,开始测试,假如实现了 OnTheFlyPrimeTable 和PreCalculatedPrimeTable
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> PrimeTableImplementations;// #define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix,SuiteName,Types,__VA_ARGS__...)
INSTANTIATE_TYPED_TEST_SUITE_P(instance_name, testcase, typelist...)

例子

template <class T>
class PrimeTableTest2 : public PrimeTableTest<T> {};// Then, declare the test case.  The argument is the name of the test
// fixture, and also the name of the test case (as usual).  The _P
// suffix is for "parameterized" or "pattern".
TYPED_TEST_SUITE_P(PrimeTableTest2);// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test,
// similar to what you do with TEST_F.
TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) {EXPECT_FALSE(this->table_->IsPrime(-5));EXPECT_FALSE(this->table_->IsPrime(0));EXPECT_FALSE(this->table_->IsPrime(1));EXPECT_FALSE(this->table_->IsPrime(4));EXPECT_FALSE(this->table_->IsPrime(6));EXPECT_FALSE(this->table_->IsPrime(100));
}TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) {EXPECT_TRUE(this->table_->IsPrime(2));EXPECT_TRUE(this->table_->IsPrime(3));EXPECT_TRUE(this->table_->IsPrime(5));EXPECT_TRUE(this->table_->IsPrime(7));EXPECT_TRUE(this->table_->IsPrime(11));EXPECT_TRUE(this->table_->IsPrime(131));
}TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) {EXPECT_EQ(2, this->table_->GetNextPrime(0));EXPECT_EQ(3, this->table_->GetNextPrime(2));EXPECT_EQ(5, this->table_->GetNextPrime(3));EXPECT_EQ(7, this->table_->GetNextPrime(5));EXPECT_EQ(11, this->table_->GetNextPrime(7));EXPECT_EQ(131, this->table_->GetNextPrime(128));
}// Type-parameterized tests involve one extra step: you have to
// enumerate the tests you defined:
REGISTER_TYPED_TEST_SUITE_P(PrimeTableTest2,  // The first argument is the test case name.// The rest of the arguments are the test names.ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);// At this point the test pattern is done.  However, you don't have
// any real test yet as you haven't said which types you want to run
// the tests with.// To turn the abstract test pattern into real tests, you instantiate
// it with a list of types.  Usually the test pattern will be defined
// in a .h file, and anyone can #include and instantiate it.  You can
// even instantiate it more than once in the same program.  To tell
// different instances apart, you give each of them a name, which will
// become part of the test case name and can be used in test filters.// The list of types we want to test.  Note that it doesn't have to be
// defined at the time we write the TYPED_TEST_P()s.
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>PrimeTableImplementations;
INSTANTIATE_TYPED_TEST_SUITE_P(OnTheFlyAndPreCalculated,    // Instance namePrimeTableTest2,             // Test case namePrimeTableImplementations);  // Type list

事件

可以通过 googletest 的事件机制,在测试前后进行埋点处理

// The interface for tracing execution of tests. The methods are organized in the order the corresponding events are fired.
class TestEventListener {public:virtual ~TestEventListener() {}// Fired before any test activity starts.virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;  //单元测试前调用// Fired before each iteration of tests starts. // There may be more than one iteration if GTEST_FLAG(repeat) is set. // iteration is the iteration index, starting from 0.virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0;// Fired before environment set-up for each iteration of tests starts.virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;  //设置环境// Fired after environment set-up for each iteration of tests ends.virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;// Fired before the test suite starts.virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {}// Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_// Fired before the test starts.virtual void OnTestStart(const TestInfo& test_info) = 0;// Fired after a failed assertion or a SUCCEED() invocation.// If you want to throw an exception from this function to skip to the next// TEST, it must be AssertionException defined above, or inherited from it.virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;// Fired after the test ends.virtual void OnTestEnd(const TestInfo& test_info) = 0;// Fired after the test suite ends.virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {}// Legacy API is deprecated but still available
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_// Fired before environment tear-down for each iteration of tests starts.virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;// Fired after environment tear-down for each iteration of tests ends.virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;// Fired after each iteration of tests finishes.virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0;// Fired after all test activities have ended.virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;  //单元测试结束后调用
};

注意OnTestProgramStart、OnTestProgramEnd与OnEnvironmentsSetUpStart、OnEnvironmentsSetUpEnd的区别。两者虽然都是全局的,后方是在环境初始化时调用,也就是在main函数中的InitGoogleTest函数中调用。
例子,注意需要自己写main函数

class TersePrinter : public EmptyTestEventListener {private:// Called before any test activity starts.void OnTestProgramStart(const UnitTest& /* unit_test */) override {}// Called after all test activities have ended.void OnTestProgramEnd(const UnitTest& unit_test) override {fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");fflush(stdout);}// Called before a test starts.void OnTestStart(const TestInfo& test_info) override {fprintf(stdout,"*** Test %s.%s starting.\n",test_info.test_case_name(),test_info.name());fflush(stdout);}// Called after a failed assertion or a SUCCEED() invocation.void OnTestPartResult(const TestPartResult& test_part_result) override {fprintf(stdout,"%s in %s:%d\n%s\n",test_part_result.failed() ? "*** Failure" : "Success",test_part_result.file_name(),test_part_result.line_number(),test_part_result.summary());fflush(stdout);}// Called after a test ends.void OnTestEnd(const TestInfo& test_info) override {fprintf(stdout,"*** Test %s.%s ending.\n",test_info.test_case_name(),test_info.name());fflush(stdout);}
};  // class TersePrinterTEST(CustomOutputTest, PrintsMessage) {printf("Printing something from the test body...\n");
}TEST(CustomOutputTest, Succeeds) {SUCCEED() << "SUCCEED() has been invoked from here";
}TEST(CustomOutputTest, Fails) {EXPECT_EQ(1, 2)<< "This test fails in order to demonstrate alternative failure messages";
}
}  // namespaceint main(int argc, char **argv) {InitGoogleTest(&argc, argv);bool terse_output = false;if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 )terse_output = true;elseprintf("%s\n", "Run this program with --terse_output to change the way ""it prints its output.");UnitTest& unit_test = *UnitTest::GetInstance();// If we are given the --terse_output command line flag, suppresses the// standard output and attaches own result printer.if (terse_output) {TestEventListeners& listeners = unit_test.listeners();// Removes the default console output listener from the list so it will// not receive events from Google Test and won't print any output. Since// this operation transfers ownership of the listener to the caller we// have to delete it as well.delete listeners.Release(listeners.default_result_printer());// Adds the custom output listener to the list. It will now receive// events from Google Test and print the alternative output. We don't// have to worry about deleting it since Google Test assumes ownership// over it after adding it to the list.listeners.Append(new TersePrinter);}int ret_val = RUN_ALL_TESTS();// This is an example of using the UnitTest reflection API to inspect test// results. Here we discount failures from the tests we expected to fail.int unexpectedly_failed_tests = 0;for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {const testing::TestSuite& test_suite = *unit_test.GetTestSuite(i);for (int j = 0; j < test_suite.total_test_count(); ++j) {const TestInfo& test_info = *test_suite.GetTestInfo(j);// Counts failed tests that were not meant to fail (those without// 'Fails' in the name).if (test_info.result()->Failed() &&strcmp(test_info.name(), "Fails") != 0) {unexpectedly_failed_tests++;}}}// Test that were meant to fail should not affect the test program outcome.if (unexpectedly_failed_tests == 0)ret_val = 0;return ret_val;
}

例子

举个例子,检测内存泄漏。
new 是c++的关键字,主要做两步:

  1. 调用 operator new 分配内存
  2. 调用构造函数在步骤 1 返回的内存地址生成类对象

我们可以通过重载 new 来修改 1 的功能。
delete 与 new 类似,只是是先调用析构函数,再释放内存,我们也可以重载delete函数。

// 重载操作符 new 和 delete,接着用类的静态成员来统计调用 new 和 delete的次数
class CLeakMem {public:
...void* operator new(size_t allocation_size) {allocated_++;return malloc(allocation_size);}void operator delete(void* block, size_t /* allocation_size */) {allocated_--;free(block);}
private:static int allocated_;
};int CLeakMem::allocated_ = 0;class LeakChecker : public EmptyTestEventListener {private:// Called before a test starts.void OnTestStart(const TestInfo& /* test_info */) override {initially_allocated_ = Water::allocated();}// Called after a test ends.void OnTestEnd(const TestInfo& /* test_info */) override {int difference = Water::allocated() - initially_allocated_;// You can generate a failure in any event handler except OnTestPartResult. Just use an appropriate Google Test assertion to do it.EXPECT_LE(difference, 0) << "Leaked " << difference << " unit(s) of class!";}int initially_allocated_;
};

googlemock

当你写一个原型或测试,往往不能完全的依赖真实对象。一个 mock 对象实现与一个真实对象相同的接口,但让你在运行时指定它时,如何使用?它应该做什么?(哪些方法将被调用?什么顺序?多少次?有什么参数?会返回什么?等)
可以模拟检查它自己和调用者之间的交互,mock 用于创建模拟类和使用它们:

  • 使用一些简单的宏描述你想要模拟的接口,他们将扩展到你的 mock 类的实现
  • 创建一些模拟对象,并使用直观的语法指定其期望和行为
  • 练习使用模拟对象的代码。 Google Mock会在出现任何违反期望的情况时立即处理

注意googlemock 依赖 googletest;调用 InitGoogleMock 时会自动调用 InitGoogleTest。

适用场景

  • 测试很慢,依赖于太多的库或使用昂贵的资源
  • 测试脆弱,使用的一些资源是不可靠的(例如网络)
  • 测试代码如何处理失败(例如,文件校验和错误),但不容易造成失败
  • 确保模块以正确的方式与其他模块交互,但是很难观察到交互。因此你希望看到观察行动结束时的副作用
  • 想模拟出复杂的依赖

使用步骤

第一步,编写模拟类

#include "gmock/gmock.h" // Brings in Google Mock.
class MockTurtle : public Turtle {public:
...//只是说明语法,不一定是这样调用MOCK_METHOD0(PenUp, void());MOCK_METHOD0(PenDown, void());MOCK_METHOD1(Forward, void(int distance));MOCK_METHOD1(Turn, void(int degrees));MOCK_METHOD2(GoTo, void(int x, int y));MOCK_CONST_METHOD0(GetX, int());MOCK_CONST_METHOD0(GetY, int());
};

第二步,设置期望

EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);

第三步,调用

mock_object obj;
t1 = obj.func1();
t2 = objfunc2();

说明一下里面的参数
matchers:期待参数

EXPECT_CALL(turtle, Forward(100));

cardinality:调用次数

// turtle::Forward 将预期调用1次
EXPECT_CALL(turtle, Forward(100)).Times(1);
// turtle::Forward 将预期调用至少1次
EXPECT_CALL(turtle, Forward(100)).Times(AtLeast(1));

action:满足期望做什么

using ::testing::Return;
...
// GetX 第一次调用返回100,第二次调用返回200,第三次返回300
EXPECT_CALL(turtle, GetX()).Times(3).WillOnce(Return(100)).WillOnce(Return(200)).WillOnce(Return(300));// GetX 第一次调用返回100,第二次调用返回200,第三次返回0
EXPECT_CALL(turtle, GetX()).Times(3).WillOnce(Return(100)).WillOnce(Return(200));// GetX 将会返回4次100; WillRepeatedly 中的表达式只会计算一次
int n = 100;
EXPECT_CALL(turtle, GetX()).Times(4).WillRepeatedly(Return(n++));// #2 将会覆盖 #1;调用第三次将会报错
EXPECT_CALL(turtle, Forward(_)); // #1
EXPECT_CALL(turtle, Forward(10)) // #2.Times(2);// 将严格按照 PenDown, Forward, PenUp 调用顺序检查
EXPECT_CALL(turtle, PenDown());
EXPECT_CALL(turtle, Forward(100));
EXPECT_CALL(turtle, PenUp());

例子

class FooInterface {public:virtual ~FooInterface() {}virtual std::string getArbitraryString() = 0;virtual int getPosition() = 0;
};class MockFoo : public FooInterface {public:MOCK_METHOD0(getArbitraryString, std::string());MOCK_METHOD0(getPosition, int());
};#include "stdafx.h"
using namespace seamless;
using namespace std;
using ::testing::Return;int main(int argc, char** argv) {::testing::InitGoogleMock(&argc, argv);int n = 100;string value = "Hello World!";MockFoo mockFoo;EXPECT_CALL(mockFoo, getArbitraryString()).Times(1).WillOnce(Return(value));string returnValue = mockFoo.getArbitraryString();cout << "Returned Value: " << returnValue << endl;//在这里Times(2)意思是调用两次,但是下边只调用了一次,所以会报出异常EXPECT_CALL(mockFoo, getPosition()).Times(2).WillRepeatedly(Return(n++));int val = mockFoo.getPosition(); //100cout << "Returned Value: " << val << endl;//getPosition指定了调用两次,这里只调用了一次,所以运行结果显示出错return EXIT_SUCCESS;
}

提示一下,这里虽然介绍了这么多,一般不使用googlemock。因为googlemock是参照python和java的mock组件做的,而python和java的mock组件已经成熟,比如模拟类已经不需要我们手写了,有个工具能自动生成。如果要自己手写,可能需要写很长代码,实现起来比较麻烦。

googletest简介相关推荐

  1. 关于单元测试框架GoogleTest——参考《百度文库》、大量博客

    本文章集齐百家之所长(又臭又长),读者可根据自己的需求自取: 一.关于测试 1.1 为啥要测试? 1.2 测试的分类 1.3 [单元测试-参考web[song]的博客] 1.3.1.为什么单元测试? ...

  2. GoogleTest使用教程

    1.简介 GoogleTest是由Google开发的一个C++测试框架,支持Linux.Windows和macOS操作系统,使用Bazel或CMake构建工具. 项目主页:https://github ...

  3. 【gTest】gtest简介及简单使用

    [gTest]gtest简介及简单使用 gtest是一个跨平台(Liunx.Mac OS X.Windows.Cygwin.Windows CE and Symbian)的C++测试框架,有googl ...

  4. GoogleTest单元测试学习

    一.GTest简介 GoogleTest是一个单元测试的框架. 单元测试: 单元测试在函数在整个工程运行起来之前,对该函数进行测试,来判断当前函数能否达到预期的效果. 使用GoogleTest: 1. ...

  5. LevelDb(一):LevelDb简介

    1. leveldb简介 2. hello world     2.1 leveldb源码下载和编译     2.2 hello world程序 1. leveldb简介 LevelDb是google ...

  6. etcd 笔记(01)— etcd 简介、特点、应用场景、常用术语、分布式 CAP 理论、分布式原理

    1. etcd 简介 etcd 官网定义: A highly-available key value store for shared configuration and service discov ...

  7. Docker学习(一)-----Docker简介与安装

    一.Docker介绍 1.1什么是docker Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源 Docker可以让开发者打包他们的应用以及依赖包到一个轻量级,可移植 ...

  8. 【Spring】框架简介

    [Spring]框架简介 Spring是什么 Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Asp ...

  9. TensorRT简介

    TensorRT 介绍 引用:https://arleyzhang.github.io/articles/7f4b25ce/ 1 简介 TensorRT是一个高性能的深度学习推理(Inference) ...

最新文章

  1. npm start 作用
  2. mac 下周期调度命令或脚本
  3. python截取html图片大小,Python打开html文件,截取屏幕截图,裁剪并保存为图像
  4. Machine Learning - Andrew Ng on Coursera (Week 3)
  5. Executor 执行器接口笔记
  6. malloc和free实现的原理
  7. python ssh登陆模块_使用python的Paramiko模块登陆SSH
  8. 超像素分割算法matlab_像素不够,算法来凑。这个图像超分辨率项目帮你「拍」出高清照片...
  9. base32解码工具_[随波逐流]CTF编码工具 V1.0
  10. 常考的java数据库笔试题
  11. HTML5 基础入门教程
  12. 8位数码管动态扫描显示c语言,proteus仿真之8位数码管动态扫描显示试验
  13. MacCMS v10 播放器配置 无法保存
  14. series not exists. Legend data should be same with series name or data name. 问题VUE ECHARTS
  15. 基于CNN的花卉识别
  16. 修改热血传奇服务器地址,传奇私服如何更改上线地点
  17. 微信公众号之刷卡支付
  18. 知到网课中国饮食文化单元测试试题答案总结
  19. 攻防世界-MISC-练习区-12(功夫再高也怕菜刀)
  20. scrapy+crawlspider+增量式爬取电影

热门文章

  1. K8S系列:no kind “Deployment“ is registered for version apps/v1
  2. 麒麟 嵌入式linux操作系统_体验了一下北韩操作系统RedStar红星OS;国产linux优麒麟...
  3. cassandra实战--物化视图(Materialized View)
  4. Esper学习之十:EPL语法(六)
  5. Kotlin 学习笔记(四)—— 协程的基础知识,面试官的最爱了~
  6. 高光谱遥感--原理、技术与应用(童庆禧院士等)
  7. 那些牛逼互联网公司里技术团队的博客
  8. js实现多图上传和预览(包含表单上传、ajax上传)
  9. Materia切换动画
  10. Bidirectional A*