假设您的示例的第一部分是被测源代码,第二部分是单元测试,那么您需要选择如何处理它:
一些开源框架,如BDE和Boost,有自己的 ASSERT 宏,可以在应用程序启动时进行配置,使其行为不同于 C 断言。例如,您可以指定失败的 ASSERT 引发异常 - 然后您可以使用 Catch 的REQUIRE_THROWS()断言来验证您的代码是否强制执行它是非 NULL 文件描述符协定。
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 一样。