gtest使用简介

本文是关于Google的开源C++测试框架gtest的介绍。gtest提供了一种简单实用的方法来编写测试用例,包括如何创建测试用例、断言、测试覆盖率以及使用mock和fake对象进行测试。通过gtest,开发者可以方便地组织和运行测试,同时支持生成测试报告和进行异常处理。文章还详细讲解了gtest中的各种断言、测试用例组织、死亡测试、泛型测试和mock/fake对象的使用。
摘要由CSDN通过智能技术生成

             gtest使用简介

       gtest是谷歌开发的开源测试框架,用于帮助c++开发者实现测试用例。使用下来感觉gtest简单实用,基本可以满足各类的测试需求。

gtest的使用并不复杂,这里主要是整理一下基本的使用方法和一些实际开发中碰到的问题。通过 https://github.com/google/googletest 可以得到源码,也有比较详细的使用说明。

一. 一个简单的例子

以下例子来自于gtest源码下提供的sample。

C++
int Factorial(int n) {
  int result = 1;
  for (int i = 1; i <= n; i++) {
    result *= i;
  }

  return result;
}

以上是一个计算阶乘的函数,我们需要写测试代码验证它的正确性。

C++
#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);

  // <TechnicalDetails>
  //
  // EXPECT_EQ(expected, actual) is the same as
  //
  //   EXPECT_TRUE((expected) == (actual))
  //
  // except that it will print both the expected value and the actual
  // value when the assertion fails.  This is very helpful for
  // debugging.  Therefore in this case EXPECT_EQ is preferred.
  //
  // On the other hand, EXPECT_TRUE accepts any Boolean expression,
  // and is thus more general.
  //
  // </TechnicalDetails>
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) { EXPECT_EQ(1, Factorial(0)); }

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
  EXPECT_EQ(1, Factorial(1));
  EXPECT_EQ(2, Factorial(2));
  EXPECT_EQ(6, Factorial(3));
  EXPECT_EQ(40320, Factorial(8));
}

    如上,测试代码的实现,都通过宏TEST来开始:

C++
#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name)

TEST需要两个参数:第一个是test suite的名字,test suite代表一组相关的测试脚本,比如如上的三个Test的test suite的名字都是FactorialTest,都是针对于函数Factorial的测试;第二参数是为当前测试块的名字。这样做的目的是为了能将测试用例分成不同的层次,当在开发过程中,你只希望针对一些特殊的用例进行测试的时候,可以通过 --gtest_filter 来选择只运行指定的用例。

        TEST展开的结果,简单理解就是它会生成一个名字为test_suite_name##_##test_name##_Test

的类,该类继承于gtest提供的类Test。比如 TEST(FactorialTest, Zero) 展开的大概样子:

C++
  class FactorialTest_Zeor_Test
      : public Test {
    ......
    private:                                                                    
      void TestBody() override;                                                  
      static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;
    }
    
    ::testing::TestInfo* const FactorialTest_Zeor_Test ::test_info_ =   
      ::testing::internal::MakeAndRegisterTestInfo("Factorialtest", "Zeor_Test",
          nullptr, nullptr, ..., new TestFactoryImpl<FactorialTest_Zeor_Test>) ;

  void FactorialTest_Zeor_Test::TestBody() {
      EXPECT_EQ(1, Factorial(0));
  }

      TEST展开后,TEST()后跟着的{}中的内容,就是TestBody的实现。这里的TestBody是继承类Test中虚函数的实现。

再简单看一下test_info_ ,是一个静态变量。在FactorialTest_Zeor_Test中,其实它并没有被用到。它存在的目的是通过MakeAndRegisterTestInfo函数,将test_suite_name,test_name,以及这里定义的FactorialTest_Zeor_Test保存到到一个单例对象中:

C++
UnitTest* UnitTest::GetInstance() {
  // CodeGear C++Builder insists on a public destructor for the
  // default implementation.  Use this implementation to keep good OO
  // design with private destructor.

#if defined(__BORLANDC__)
  static UnitTest* const instance = new UnitTest;
  return instance;
#else
  static UnitTest instance;
  return &instance;
#endif  // defined(__BORLANDC__)
}

       这里的组织形式,

C++
 在 UnitTestImpl中定义了 test_suites_
 // The vector of TestSuites in their original order.  It owns the
  // elements in the vector.
  std::vector<TestSuite*> test_suites_;
  
  在 TestSuite 中有一下定义了 test_info_list_
    // The vector of TestInfos in their original order.  It owns the
  // elements in the vector.
  std::vector<TestInfo*> test_info_list_;

   

    在程序启动阶段,TEST定义的所有信息就会按照以上的形式保存到对应的vecotr中。

    回看一下MakeAndRegisterTestInfo中的最后一个参数 new TestFactoryImpl<FactorialTest_Zeor_Test>。这里构建了一个TestFactoryImpl的模板对象:

C++
// Defines the abstract factory interface that creates instances
// of a Test object.
class TestFactoryBase {
 public:
  virtual ~TestFactoryBase() {}

  // Creates a test instance to run. The instance is both created and destroyed
  // within TestInfoImpl::Run()
  virtual Test* CreateTest() = 0;
  TestFactoryBase() {}

 private:
  TestFactoryBase(const TestFactoryBase&) = delete;
  TestFactoryBase& operator=(const TestFactoryBase&) = delete;
};
// This class provides implementation of TestFactoryBase interface.
// It is used in TEST and TEST_F macros.
template <class TestClass>
class TestFactoryImpl : public TestFactoryBase {
 public:
  Test* CreateTest() override { return new TestClass; }
};

这是个工厂类,目的就是生成以上定义的Test的子类(FactorialTest_Zeor_Test),工厂类对象被保存到了TestInfo中。

C++
  internal::TestFactoryBase* const factory_;  // The factory that creates
                                              // the test object

通过以上的组织方式,不再需要使用者再写其它代码去运行测试用例。而由统一的main函数来完成:

C++
GTEST_API_ int main(int argc, char** argv) {
  // Since Google Mock depends on Google Test, InitGoogleMock() is
  // also responsible for initializing Google Test.  Therefore there's
  // no need for calling testing::InitGoogleTest() separately.
  testing::InitGoogleMock(&argc, argv);
  return RUN_ALL_TESTS();
}

     一般main函数,如上形式。没有特殊需求时候,不需要修改main函数,RUN_ALL_TESTS会根据之前保存到vector中的信息,去运行测试用例。

二. 运行结果

  编译以上的程序,生成可执行文件sample1_unittest.exe。运行结果如下:

Bash
D:\code\googletest-main\out\build\x64-Debug\googletest>sample1_unittest.exe --gtest_filter=FactorialTest.*
Running main() from D:\code\googletest-main\googletest\src\gtest_main.cc
Note: Google Test filter = FactorialTest.*
[==========] Running 3 tests from 1 test suite.
[----------] 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 (3 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (9 ms total)
[  PASSED  ] 3 tests.

可以修改一下,得到一些错误结果。

Bash
D:\code\googletest-main\out\build\x64-Debug\googletest>sample1_unittest.exe --gtest_filter=FactorialTest.*
Running main() from D:\code\googletest-main\googletest\src\gtest_main.cc
Note: Google Test filter = FactorialTest.*
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
D:\code\googletest-main\googletest\samples\sample1_unittest.cc(100): error: Expected equality of these values:
  10
  Factorial(0)
    Which is: 1
[  FAILED  ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
D:\code\googletest-main\googletest\samples\sample1_unittest.cc(107): error: Expected equality of these values:
  40310
  Factorial(8)
    Which is: 40320
[  FAILED  ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (1 ms total)

[----------] Global test environment tear-down
[==========] 3 tests from 1 test suite ran. (5 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 2 tests, listed below:
[  FAILED  ] FactorialTest.Zero
[  FAILED  ] FactorialTest.Positive

 2 FAILED TESTS

比如将 Factorial(0) 的期望值改为10,如上图测试程序将报出错误信息以及代码所在位置。

       除了在终端显示外,还可以生成文档报告:

Bash
--gtest_output=(json|xml)[:DIRECTORY_PATH\|:FILE_PATH]

      通过指定--gtest_output可以生成xml或者json文件形式的报告。

三. 测试覆盖率(另一个简单的例子)

在实际的开发过程中,项目中往往要求测试覆盖率,要求尽可能多的覆盖到所有的分支。简单看一下可能要注意到内容:

C++
// Returns true if and only if n is a prime number.
bool IsPrime(int n) {
  // Trivial case 1: small numbers
  if (n <= 1) return false;

  // Trivial case 2: even numbers
  if (n % 2 == 0) return n == 2;

  // Now, we have that n is odd and n >= 3.

  // Try to divide n by every odd number i, starting from 3
  for (int i = 3;; i += 2) {
    // We only have to try i up to the square root of n
    if (i > n / i) break;

    // Now, we have i <= n/i < n.
    // If n is divisible by i, n is not prime.
    if (n % i == 0) return false;<

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值