Можно ли использовать C ++ CATCH
рамки для проверки того, что assert
В заявлении правильно указана неверная предпосылка?
// Source code
void loadDataFile(FILE* input) {
assert(input != NULL);
...
}
// Test code
TEST_CASE("loadDataFile asserts out when passed NULL", "[loadDataFile]") {
loadDataFile(NULL)
// Now what do I look for?
}
Предполагая, что первый раздел вашего примера — это тестируемый исходный код, а вторая часть — это модульный тест, вам нужно будет сделать выбор:
Некоторые платформы с открытым исходным кодом, такие как BDE а также Увеличение имеют собственный макрос ASSERT, который можно настроить при запуске приложения, чтобы он вел себя не так, как C assert. Например, вы можете указать, что сбойный 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 (). Это заново изобретать колесо — см. Примеры выше.
Вы можете изменить свой код, чтобы бросить станд :: 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;
}
…но при этом существует риск того, что клиенты не проверяют возвращаемое значение, причину множества ошибок, и снова чувствуют себя как С.
Вы можете быть заинтересованы в Google Test Framework. Он может отлавливать аварийное завершение программы с помощью:
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