2016-07-22 50 views
2

是否可以使用C++ CATCH框架來驗證assert語句是否正確識別了無效的前提條件?使用C++ catch框架驗證斷言語句

// 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? 
} 
+1

我不知道趕,但谷歌測試所謂的_death tests_。 –

+1

你可以推出自己的'assert'宏嗎?你可以給它一個可定製的「斷言處理程序」,它會在測試項目中拋出失敗,並以其他方式終止。然後在你的測試中,你可以檢查拋出的'AssertException'。 – KABoissonneault

+0

請檢查我的答案在這裏:https://stackoverflow.com/questions/37499284/how-to-suppress-termination-in-google-test-when-assert-unexpectedly-triggers/37503591#37503591 – deniss

回答

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

您可能感興趣的谷歌測試框架。它已經趕上程序異常終止與能力:

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); 

stderr predicateregex匹配的文本程序的退出碼是否一致。

我懷疑這是通過在斷言前分叉測試程序來實現的。

文檔瀏覽:

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

+0

@chris我的錯誤。我把問題和評論混爲一談。將修復。 –