我想测试在某种情况下抛出MyException
。 EXPECT_THROW
在这里很好。但我还想检查异常是否具有特定状态,例如e.msg() == "Cucumber overflow"
。
如何在GTest中实现最佳效果?
答案 0 :(得分:42)
我主要是第二个Lilshieste的答案,但会补充说你也应该这样做 验证是否未抛出错误的异常类型:
#include <stdexcept>
#include "gtest/gtest.h"
struct foo
{
int bar(int i) {
if (i > 100) {
throw std::out_of_range("Out of range");
}
return i;
}
};
TEST(foo_test,out_of_range)
{
foo f;
try {
f.bar(111);
FAIL() << "Expected std::out_of_range";
}
catch(std::out_of_range const & err) {
EXPECT_EQ(err.what(),std::string("Out of range"));
}
catch(...) {
FAIL() << "Expected std::out_of_range";
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
答案 1 :(得分:29)
一位同事通过重新抛出异常来提出解决方案。
诀窍:不需要额外的FAIL()语句,只需要测试你真正想要的两个EXPECT ...调用:这样的异常及其值。
TEST(Exception, HasCertainMessage )
{
// this tests _that_ the expected exception is thrown
EXPECT_THROW({
try
{
thisShallThrow();
}
catch( const MyException& e )
{
// and this tests that it has the correct message
EXPECT_STREQ( "Cucumber overflow", e.what() );
throw;
}
}, MyException );
}
答案 2 :(得分:15)
Jeff Langr在他的书Modern C++ Programming with Test-Driven Development中描述了一种很好的方法:
如果您的[testing]框架不支持确保抛出异常的单行声明性断言,则可以在测试中使用以下结构:
TEST(ATweet, RequiresUserNameToStartWithAnAtSign) { string invalidUser("notStartingWith@"); try { Tweet tweet("msg", invalidUser); FAIL(); } catch(const InvalidUserException& expected) {} }
[...] 如果必须在抛出异常后验证任何后置条件,则可能还需要使用try-catch结构。例如,您可能希望验证与抛出的异常对象关联的文本。
TEST(ATweet, RequiresUserNameToStartWithAtSign) { string invalidUser("notStartingWith@"); try { Tweet tweet("msg", invalidUser); FAIL(); } catch(const InvalidUserException& expected) { ASSERT_STREQ("notStartingWith@", expected.what()); } }
(第95页)
这是我使用过的方法,并且已经在其他地方看到了。
编辑正如@MikeKinghan所指出的那样,完全不匹配EXPECT_THROW
提供的功能;如果抛出错误的异常,测试不会失败。可以添加一个额外的catch
子句来解决这个问题:
catch(...) {
FAIL();
}
答案 3 :(得分:2)
我的版本;它产生与EXPECT_THROW相同的输出,只是添加了字符串test:
#define EXPECT_THROW_MSG(statement, expected_exception, expected_what) \
try \
{ \
statement; \
FAIL() << "Expected: " #statement " throws an exception of type " #expected_exception \
".\n" \
" Actual: it throws nothing."; \
} \
catch (const expected_exception& e) \
{ \
EXPECT_EQ(expected_what, std::string{e.what()}); \
} \
catch (...) \
{ \
FAIL() << "Expected: " #statement " throws an exception of type " #expected_exception \
".\n" \
" Actual: it throws a different type."; \
}
答案 4 :(得分:1)
我建议根据Mike Kinghan的方法定义一个新的宏。
#define ASSERT_EXCEPTION( TRY_BLOCK, EXCEPTION_TYPE, MESSAGE ) \
try \
{ \
TRY_BLOCK \
FAIL() << "exception '" << MESSAGE << "' not thrown at all!"; \
} \
catch( const EXCEPTION_TYPE& e ) \
{ \
EXPECT_EQ( MESSAGE, e.what() ) \
<< " exception message is incorrect. Expected the following " \
"message:\n\n" \
<< MESSAGE << "\n"; \
} \
catch( ... ) \
{ \
FAIL() << "exception '" << MESSAGE \
<< "' not thrown with expected type '" << #EXCEPTION_TYPE \
<< "'!"; \
}
Mike的TEST(foo_test,out_of_range)
示例将是
TEST(foo_test,out_of_range)
{
foo f;
ASSERT_EXCEPTION( { f.bar(111); }, std::out_of_range, "Out of range" );
}
我觉得最终会更具可读性。
答案 5 :(得分:1)
由于我需要做几个这样的测试,我写了一个宏,基本上包括Mike Kinghan的答案,但是&#34;删除&#34;所有样板代码:
#define ASSERT_THROW_KEEP_AS_E(statement, expected_exception) \
std::exception_ptr _exceptionPtr; \
try \
{ \
(statement);\
FAIL() << "Expected: " #statement " throws an exception of type " \
#expected_exception ".\n Actual: it throws nothing."; \
} \
catch (expected_exception const &) \
{ \
_exceptionPtr = std::current_exception(); \
} \
catch (...) \
{ \
FAIL() << "Expected: " #statement " throws an exception of type " \
#expected_exception ".\n Actual: it throws a different type."; \
} \
try \
{ \
std::rethrow_exception(_exceptionPtr); \
} \
catch (expected_exception const & e)
ASSERT_THROW_KEEP_AS_E(foo(), MyException)
{
ASSERT_STREQ("Cucumber overflow", e.msg());
}
std::exception_ptr
答案 6 :(得分:0)
我喜欢大多数答案。但是,由于GoogleTest似乎提供的EXPECT_PRED_FORMAT有助于实现此目的,因此我想将此选项添加到答案列表中:
MyExceptionCreatingClass testObject; // implements TriggerMyException()
EXPECT_PRED_FORMAT2(ExceptionChecker, testObject, "My_Expected_Exception_Text");
其中ExceptionChecker定义为:
testing::AssertionResult ExceptionChecker(const char* aExpr1,
const char* aExpr2,
MyExceptionCreatingClass& aExceptionCreatingObject,
const char* aExceptionText)
{
try
{
aExceptionCreatingObject.TriggerMyException();
// we should not get here since we expect an exception
return testing::AssertionFailure() << "Exception '" << aExceptionText << "' is not thrown.";
}
catch (const MyExpectedExceptionType& e)
{
// expected this, but verify the exception contains the correct text
if (strstr(e.what(), aExceptionText) == static_cast<const char*>(NULL))
{
return testing::AssertionFailure()
<< "Exception message is incorrect. Expected it to contain '"
<< aExceptionText << "', whereas the text is '" << e.what() << "'.\n";
}
}
catch ( ... )
{
// we got an exception alright, but the wrong one...
return testing::AssertionFailure() << "Exception '" << aExceptionText
<< "' not thrown with expected type 'MyExpectedExceptionType'.";
}
return testing::AssertionSuccess();
}
答案 7 :(得分:0)
我使用MatthäusBrandl的宏进行了以下微小修改:
放线
std::exception_ptr _exceptionPtr;
外部(f.e. before)宏定义为
static std::exception_ptr _exceptionPtr;
避免对符号_exceptionPtr
进行多重定义。
答案 8 :(得分:0)
扩展先前的答案,该宏用于验证是否抛出了给定类型的异常,并且其消息以提供的字符串开头。
如果没有引发异常,异常类型错误或消息不是以提供的字符串开头,则测试失败。
#define ASSERT_THROWS_STARTS_WITH(expr, exc, msg) \
try\
{\
(expr);\
FAIL() << "Exception not thrown";\
}\
catch (const exc& ex)\
{\
EXPECT_THAT(ex.what(), StartsWith(std::string(msg)));\
}\
catch(...)\
{\
FAIL() << "Unexpected exception";\
}
用法示例:
ASSERT_THROWS_STARTS_WITH(foo(-2), std::invalid_argument, "Bad argument: -2");
答案 9 :(得分:0)
我建议使用
EXPECT_THROW(function_that_will_throw(), exception);
如果你的函数返回无效的东西:
EXPECT_THROW((void)function_that_will_throw(), exception);
答案 10 :(得分:0)
我之前在 an older answer 中提供了一个宏来解决这个问题。然而,随着时间的流逝,GTest 中添加了一项新功能,无需宏即可实现这一点。
该特征是一组匹配器,例如,可以与 Throws
结合使用的 EXPECT_THAT()
。但是文档似乎没有更新,所以唯一的信息隐藏在 this GitHub issue 中。
该功能是这样使用的:
EXPECT_THAT([]() { throw std::runtime_error("message"); },
Throws<std::runtime_error>());
EXPECT_THAT([]() { throw std::runtime_error("message"); },
ThrowsMessage<std::runtime_error>(HasSubstr("message")));
EXPECT_THAT([]() { throw std::runtime_error("message"); },
ThrowsMessageHasSubstr<std::runtime_error>("message"));
EXPECT_THAT([]() { throw std::runtime_error("message"); },
Throws<std::runtime_error>(Property(&std::runtime_error::what,
HasSubstr("message"))));
请注意,由于 EXPECT_THAT()
的工作方式,您需要将 throwing 语句放入无需参数即可调用的内容中。因此就是上面例子中的 lambda。
另请注意,此功能未包含在 1.10 版中,但已合并到 master
中。因为 GTest 遵循绳索的现场直播政策,所以目前有 are no new versions planned。此外,他们似乎没有遵循 abseil 的政策,为那些不能/不会生活在头脑中的人发布特定版本。
答案 11 :(得分:-1)
您可以尝试Boost轻量级测试:
#include <boost/detail/lightweight_test.hpp>
#include <stdexcept>
void function_that_would_throw(int x)
{
if (x > 0) {
throw std::runtime_error("throw!");
}
}
int main() {
BOOST_TEST_THROWS(function_that_would_throw(10), std::runtime_error);
boost::report_errors();
}