使用C ++ catch框架来验证assert语句

时间:2016-07-22 18:38:03

标签: c++ assert catch-unit-test

是否可以使用C ++ swift let timing: String = data["timings"][0] as? String 框架来验证CATCH语句是否正确识别了无效的前置条件?

assert

3 个答案:

答案 0 :(得分:2)

您可能对谷歌测试框架感兴趣。它能够通过以下方式捕获异常程序终止:

ASSERT_DEATH(statement, regex);
ASSERT_DEATH_IF_SUPPORTED(statement, regex);
ASSERT_EXIT(statement, predicate, regex);

EXPECT_DEATH(statement, regex);
EXPECT_DEATH_IF_SUPPORTED(statement, regex);
EXPECT_EXIT(statement, predicate, regex);

regex匹配stderr上的文字 predicate匹配程序的退出代码。

我怀疑这可以通过在断言之前分配测试程序来实现。

文档:

https://github.com/google/googletest/blob/master/googletest/docs/advanced.md

答案 1 :(得分:1)

假设您的示例的第一部分是测试中的源代码,第二部分是单元测试,那么您需要选择如何处理:

某些开源框架(如BDEBoost)有自己的ASSERT宏,可以在应用程序启动时配置为与C断言不同。例如,您可以指定失败的ASSERT抛出异常 - 然后您可以使用Catch' REQUIRE_THROWS()断言来验证您的代码是否强制执行了它的非NULL FILE描述符合同。

BDE示例

#include <bsls_assert.h>

void loadDataFile(FILE* input) {
  BSLS_ASSERT_OPT(input != NULL);
  ...
}

TEST_CASE("loadDataFile asserts out when passed NULL", "[loadDataFile]") {
   // Opt-in to the 'throw exception on assert failure' handler
   // just for this test case.
   bsls::AssertFailureHandlerGuard guard(&bsls::Assert::failThrow);
   REQUIRE_THROWS_AS(loadDataFile(NULL), bsls::AssertFailedException);
}

提升示例

#include <boost/assert.hpp>

void loadDataFile(FILE* input) {
  BOOST_ASSERT(input != NULL);
  ...
}

namespace boost {
void assertion_failed(char const * expr, char const * function, char const * file, long line) {
    throw std::runtime_error("Assertion Failed"); // TODO: use expr, function, file, line
}
}

TEST_CASE("loadDataFile asserts out when passed NULL", "[loadDataFile]") {
   REQUIRE_THROWS(loadDataFile(NULL));
   // Now what do I look for?
}

您可以滚动自己的assert()宏。这是重新发明轮子 - 参见上面的例子。

您可以将代码更改为抛出std::invalid_argument()例外:

  void loadDataFile(FILE* input) {
    if (input == NULL) {
      throw std::invalid_argument("input file descriptor cannot be NULL");
    }
    ...
  }

您可以测试您的代码是否通过以下方式强制执行合同:

REQUIRE_THROWS_AS(loadDataFile(NULL), std::invalid_argument);

这会在您的代码中引入异常(以及处理它们的需要),这是一个比您的客户可能满意的更大的变化 - 一些公司有一个无例外规则,一些平台(例如嵌入式)不支持异常。

最后,如果你真的想,你可以改变你的代码接口以暴露合同失败:

enum LoadDataFile_Result {
  LDF_Success,
  LDF_InputIsNull,
  ...
};

LoadDataFile_Result loadDataFile(FILE* input) {
  if (input == NULL) {
    // bail out early for contract failure
    return LDF_InputIsNull;
  }
  // input is non-NULL
  ...
  return LDF_Success;
}

...但是这具有固有的风险,即客户不会检查返回值,许多错误的原因,并且感觉就像C一样。

答案 2 :(得分:0)

如果可以模拟C函数,则可以暂时将断言失败更改为异常。

例如,使用Hippomocks,您的测试用例将类似于:

#ifndef NDEBUG
TEST_CASE("loadDataFile asserts out when passed NULL", "[loadDataFile]") {
    MockRepository mocks;
    mocks.OnCallFunc(__assert_fail).Throw(nullptr);

    CHECK_THROWS_AS(loadDataFile(NULL), std::nullptr_t);
}
#endif

可移植性可能是个问题,我只在Linux上使用glibc和musl对此进行了测试。