Mr.*_*Boy 48 c++ unit-testing exception googletest
我想测试MyException在某种情况下抛出的东西.EXPECT_THROW这里很好.但我也想检查异常是否有特定的状态,例如e.msg() == "Cucumber overflow".
如何在GTest中实现最佳效果?
Mik*_*han 47
我主要是第二个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();
}
Run Code Online (Sandbox Code Playgroud)
min*_*ros 36
一位同事通过重新抛出异常提出了解决方案.
诀窍:不需要额外的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 );
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*ndl 23
我之前在一个旧的答案中提供了一个宏来解决这个问题。然而,随着时间的推移,GTest 中添加了一项新功能,无需宏即可实现此目的。
该功能是一组匹配器,例如,Throws可以与 结合使用EXPECT_THAT()。然而文档似乎没有更新,所以唯一的信息隐藏在这个 GitHub 问题中。
该功能的使用方式如下:
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"))));
Run Code Online (Sandbox Code Playgroud)
请注意,由于EXPECT_THAT()工作原理,您需要将 throwing 语句放入不带参数的可调用内容中。因此上面例子中的 lambda 表达式。
编辑:此功能从版本 1.11开始包含。
另请注意,此功能并未包含在 1.10 版本中,但已合并到master. 由于 GTest 遵循 Abseil 的 live at head 政策,因此目前没有计划推出新版本。此外,他们似乎没有遵循 Abseil 的政策,为那些不能/不会生活在头部的用户发布特定版本。
Lil*_*ste 15
Jeff Langr在他的书" 使用测试驱动开发的现代C++编程"中描述了一种很好的方法:
如果您的[testing]框架不支持确保抛出异常的单行声明性断言,则可以在测试中使用以下结构:
Run Code Online (Sandbox Code Playgroud)TEST(ATweet, RequiresUserNameToStartWithAnAtSign) { string invalidUser("notStartingWith@"); try { Tweet tweet("msg", invalidUser); FAIL(); } catch(const InvalidUserException& expected) {} }[...] 如果必须在抛出异常后验证任何后置条件,则可能还需要使用try-catch结构.例如,您可能希望验证与抛出的异常对象关联的文本.
Run Code Online (Sandbox Code Playgroud)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();
}
Run Code Online (Sandbox Code Playgroud)
GTest 于 2020 年 8 月 24 日(v1.10 后)添加了一项新功能master,我在单独的答案中对此进行了解释。不过,我会留下这个答案,因为如果您使用的版本不支持新功能,它仍然有帮助。此外,这个解决方案和类似的解决方案更容易使用。
另请参阅Bryant的解决方案,该解决方案对此进行了改进。(不再exception_ptr污染你的范围)
由于我需要做几个这样的测试,我编写了一个宏,它基本上包含Mike Kinghan的答案,但“删除”了所有样板代码:
#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)
Run Code Online (Sandbox Code Playgroud)
ASSERT_THROW_KEEP_AS_E(foo(), MyException)
{
ASSERT_STREQ("Cucumber overflow", e.msg());
}
Run Code Online (Sandbox Code Playgroud)
std::exception_ptr我建议根据 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 \
<< "'!"; \
}
Run Code Online (Sandbox Code Playgroud)
迈克的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" );
}
Run Code Online (Sandbox Code Playgroud)
我认为最终会更具可读性。
| 归档时间: |
|
| 查看次数: |
37875 次 |
| 最近记录: |