gtest进阶之gtest的高级用法

1. 前言

前面一篇【gtest保姆级教程】中我们讲解了一些gtest的入门知识,gtest除了TEST_FTEST外,还有更加高级的用法,使用这些高级用法,会让你的测试效率极大提高,往往一小段测试代码就可以生成出大量的测试集,让你的测试效率事半功倍

2. 进阶用法

2.1 Skip

GTEST_SKIP()支持忽略当前测试,不管在GTEST_SKIP()之后是不是断言失败,程序都会在遇到skip的时候跳出当前测试

TEST(SkipTest, DoesSkip) {
  GTEST_SKIP() << "Skipping single test";
  FAIL();  // Won't fail; it won't be executed
}

2.2 Death Test

我们可能有时候会写一些死测试,gtest提供了死测试断言功能,如下所示:

TEST(MyDeathTest, Foo) {
  // This death test uses a compound statement.
  ASSERT_DEATH({
    int n = 5;
    Foo(&n);
  }, "Error on line .* of Foo()");
}

TEST(MyDeathTest, NormalExit) {
  EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success");
}

TEST(MyDeathTest, KillProcess) {
  EXPECT_EXIT(KillProcess(), testing::KilledBySignal(SIGKILL),
              "Sending myself unblockable signal");
}
  • 在调用Foo(5)时,程序遇到了一个死测试,此时通过ASSERT_DEATH来退出程序,并且打印一些日志
  • 调用NormalExit()时,会打印Success,并且正常退出,返回值为0
  • 调用KillProcess()时,会打印Sending myself unblockable signal,并且发送SIGKILL信号量
    注意:
    死测试的命名的test suite必须是*DeathTest, 在fixture中,为了保证正常的测试集和死测试集,我们可以使用using或者typedef来定义一个别名,例如
class FooTest : public testing::Test { ... };

using FooDeathTest = FooTest;

TEST_F(FooTest, DoesThis) {
  // normal test
}

TEST_F(FooDeathTest, DoesThat) {
  // death test
}

2.3 参数化测试

gtest支持使用INSTANTIATE_TEST_SUITE_P() 来生成测试参数,参数的type通过testing::TestWithParam<ParamType>的模板传进去,当使用参数化时,需要使用TEST_P来进行测试,例如:

class MyTestSuite : public testing::TestWithParam<int> {};

TEST_P(MyTestSuite, MyTest)
{
  std::cout << "Example Test Param: " << GetParam() << std::endl;
}

INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10),
                         testing::PrintToStringParamName());

上面代码中GetParam()将获取testing::Range(0, 10)生成的[0, 10)的数据,testing::PrintToStringParamName()表示会在test suit中通过参数生成一个测试前缀,默认可以不加。
testing::Range表示生成一个序列,它有三个参数(start,end, step),start和end表示序列的开始与结束,step表示增加的步幅,默认step是1
gtest还提供了testing::Values来指定数值, 另外还提供了testing::Combine进行各种参数的组合成一个tuple, 例如:

enum class MyType { MY_FOO = 0, MY_BAR = 1 };

class MyTestSuite : public testing::TestWithParam<std::tuple<MyType, std::string>> {
};

INSTANTIATE_TEST_SUITE_P(
    MyGroup, MyTestSuite,
    testing::Combine(
        testing::Values(MyType::MY_FOO, MyType::MY_BAR),
        testing::Values("A", "B")));
        
TEST_P(MyTestSuite, MyTest) {
    auto param = GetParam();
    std::cout << "Example Test Param: " << (int)std::get<0>(param) << ","
              << std::get<1>(param) << std::endl;
}

组合后的四种运行结果如下:

[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from MyGroup/MyTestSuite
[ RUN      ] MyGroup/MyTestSuite.MyTest/0
Example Test Param: 0,A
[       OK ] MyGroup/MyTestSuite.MyTest/0 (0 ms)
[ RUN      ] MyGroup/MyTestSuite.MyTest/1
Example Test Param: 0,B
[       OK ] MyGroup/MyTestSuite.MyTest/1 (0 ms)
[ RUN      ] MyGroup/MyTestSuite.MyTest/2
Example Test Param: 1,A
[       OK ] MyGroup/MyTestSuite.MyTest/2 (0 ms)
[ RUN      ] MyGroup/MyTestSuite.MyTest/3
Example Test Param: 1,B
[       OK ] MyGroup/MyTestSuite.MyTest/3 (0 ms)
[----------] 4 tests from MyGroup/MyTestSuite (0 ms total)

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

2.4 Typed Tests

前面我们提到的TESTTEST_F都是一些逻辑性的测试,有时候我们可能需要对参数的类型进行测试,这时候我们就需要Typed Tests功能, Typed Tests需要使用TYPED_TEST来进行测试,例如:

template <typename T>
class FooTest : public testing::Test {
 public:
  ...
  using List = std::list<T>;
  static T shared_;
  T value_;
};

我们要测试char, int, unsigned int三种type,则使用TYPED_TEST_SUITE来进行注册

using MyTypes = ::testing::Types<char, int, unsigned int>;
TYPED_TEST_SUITE(FooTest, MyTypes);

然后在TYPED_TEST中,通过TypeParam 来获取

TYPED_TEST(FooTest, DoesBlah) {
  // Inside a test, refer to the special name TypeParam to get the type
  // parameter.  Since we are inside a derived class template, C++ requires
  // us to visit the members of FooTest via 'this'.
  TypeParam n = this->value_;

  // To visit static members of the fixture, add the 'TestFixture::'
  // prefix.
  n += TestFixture::shared_;

  // To refer to typedefs in the fixture, add the 'typename TestFixture::'
  // prefix.  The 'typename' is required to satisfy the compiler.
  typename TestFixture::List values;

  values.push_back(n);
  ...
}

TYPED_TEST(FooTest, HasPropertyA) { ... }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值