首页 > 解决方案 > 如何将 TYPED_TEST 中的一些测试用例标记为预期失败?

问题描述

我正在从事一个 C++ 学习项目,其双重目标是学习如何编写模板代码以及学习如何使用 GoogleTest。我的项目目标是实现一个工作四元数类以及使用 GoogleTest 编写的功能测试。

到目前为止,我的课程运行良好,但我想将一些 GoogleTest 测试用例标记为“预期失败”。这是四元数相关构造函数的签名 -

template <typename T>
class quaternion {
  template <typename U, typename V, typename W, typename X>
  quaternion(U u, V v, W w, X x);
};

我正在使用 GoogleTest 编写一些 TYPED_TEST 测试用例,其中我尝试使用诸如 unsigned char、char 等初始化器创建给定类型T的四元数......

这是我的类型列表

using MyTypes = ::testing::Types<char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, float, double, long double>;

这是测试夹具 -

TYPED_TEST(QuaternionTests, DirectInitialization00) {
  unsigned int i = 5, j = 235, k = 67, l = 82;
  this->SetUp(i, j, k, l);
  EXPECT_EQ(this->q.a, 5);
  EXPECT_EQ(this->q.b, 235);
  EXPECT_EQ(this->q.c, 67);
  EXPECT_EQ(this->q.d, 82);
}

其中 SetUp 只是调用四元数构造函数。

自然,当四元数的类型为char时,此测试会失败,因为四元数不能为成员b保存值 235 ( unsigned int ) 。

我的问题是 - 有没有办法在 TYPED_TEST 宏的范围内将T == charunsigned int的特定组合标记为“预期失败”?还是我必须切换到常规的 TEST 宏?

标签: c++googletest

解决方案


您可以修改测试主体来处理这种情况。据我所知,没有办法将类型参数标记为预期失败。

[例如,在 Python 的pytest框架中,这可以通过pytest.param(int, marks=pytest.mark.xfail).]

当然可以自省类型参数并从测试主体中跳过测试。Google Test现在有一个GTEST_SKIP(),我怀疑它可以从 Google Test 1.10.0 获得。

如果该宏不可用,您可以使用不太明确的SUCCEED(),然后是一条return语句:

TYPED_TEST(QuaternionTests, DirectInitialization00) { 
  // Could also check `std::numeric_limits<T>::max()` 
  // or `sizeof(T)`.
  using T = typename QuaternionTests::TypeParam;
  if constexpr (std::is_same_v<T, char>) {
    // with gtest version 1.10.0 and later (?):
    GTEST_SKIP() << "Test is not valid with T equal to `char`.";

    // or with older versions gtest:
    SUCCEED() << "Test is not valid with T equal to `char`.";
    return; 
  }

  unsigned int i = 5, j = 235, k = 67, l = 82;
  this->SetUp(i, j, k, l);

  EXPECT_EQ(this->q.a, 5);  
  EXPECT_EQ(this->q.b, 235);
  EXPECT_EQ(this->q.c, 67);
  EXPECT_EQ(this->q.d, 82);
}

另一种选择是引入一个包含标量类型的信息量更大的类型参数,以及有关是否期望成功的信息。例如:

template <typename T, bool ExpectSuccess = true>
struct QTestParam {
  using type = T;
  using expect_success = std::bool_constant<ExpectSuccess>;
};

using MyTypes = ::testing::Types<
   QTestParam<char, /*ExpectSuccess*/ false>,
   QTestParam<short int>,
   QTestParam<int>,
   QTestParam<long int>,
   QTestParam<float>,
   QTestParam<double>,
>;

然后,您可以像这样定义一个测试类模板,它以一种很好的方式提供对布尔指标的访问:

template <typename Param>
struct QuaternionTests : public ::testing::Test {
  using T = Param::type;  // scalar type such as int.

  constexpr static bool ExpectSuccess() {
    return Param::expect_success{};
  }
  constexpr static bool ExpectFailure() {
    return !ExpectSuccess();
  }
};

不幸的是,我认为单个测试需要像第一个代码片段那样实现“跳过”逻辑:

TYPED_TEST(QuaternionTests, DirectInitialization00) {
  constexpr if (ExpectFailure()) {
    GTEST_SKIP();
  }
  // [...]
};

推荐阅读