Используйте C ++ catch Framework для проверки утверждения assert

Можно ли использовать 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?
}

3

Решение

Предполагая, что первый раздел вашего примера — это тестируемый исходный код, а вторая часть — это модульный тест, вам нужно будет сделать выбор:

Некоторые платформы с открытым исходным кодом, такие как 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;
}

…но при этом существует риск того, что клиенты не проверяют возвращаемое значение, причину множества ошибок, и снова чувствуют себя как С.

1

Другие решения

Вы можете быть заинтересованы в 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

2