To test my C++ project I am using GoogleTest framework. Normally I can use the following syntax to easily debug a failure:
EXPECT_TRUE(*statement*) << *debugMessage*;
When I use the macro EXPECT_NO_THROW (or ASSERT_NO_THROW) I might of course do the same, but I do not have access to the exception object that was thrown (and caught) inside the macro itself and so the debugMessage cannot tell me anything about it.
Is it possible to show information about this exception in any way?
EDIT
Is not possible without any custom function/macro.
Here's one way:
#include <exception>
#include <stdexcept>
#include <ostream>
#include <iostream> // for the test
#include <gtest/gtest.h>
namespace detail {
struct unwrapper
{
unwrapper(std::exception_ptr pe) : pe_(pe) {}
operator bool() const {
return bool(pe_);
}
friend auto operator<<(std::ostream& os, unwrapper const& u) -> std::ostream&
{
try {
std::rethrow_exception(u.pe_);
return os << "no exception";
}
catch(std::runtime_error const& e)
{
return os << "runtime_error: " << e.what();
}
catch(std::logic_error const& e)
{
return os << "logic_error: " << e.what();
}
catch(std::exception const& e)
{
return os << "exception: " << e.what();
}
catch(...)
{
return os << "non-standard exception";
}
}
std::exception_ptr pe_;
};
}
auto unwrap(std::exception_ptr pe)
{
return detail::unwrapper(pe);
}
template<class F>
::testing::AssertionResult does_not_throw(F&& f)
{
try {
f();
return ::testing::AssertionSuccess();
}
catch(...) {
return ::testing::AssertionFailure() << unwrap(std::current_exception());
}
};
TEST(a, b)
{
ASSERT_TRUE(does_not_throw([] { throw std::runtime_error("i threw"); }));
}
example output:
Running main() from gtest_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from a
[ RUN ] a.b
/Users/rhodges/play/project/nod.cpp:66: Failure
Value of: does_not_throw([] { throw std::runtime_error("i threw"); })
Actual: false (runtime_error: i threw)
Expected: true
[ FAILED ] a.b (1 ms)
[----------] 1 test from a (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] a.b
1 FAILED TEST
An alternative to the answer by Richard Hodges, is to use a try-catch structure inside the test-body. This solution comes from the very good book Modern C++ Programming with Test-Driven Development written by Jeff Langr.
A complete working example could look like the following:
#include <stdexcept>
#include "gtest/gtest.h"
struct foo
{
void bar() {
throw std::runtime_error("unexpected error");
}
};
TEST(foo_test, does_not_throw)
{
foo f;
try {
f.bar();
SUCCEED();
}
catch (std::exception const & err) {
FAIL() << err.what();
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
And the ouput:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from foo_test
[ RUN ] foo_test.does_not_throw
/Users/Soeren/Documents/cmakeProject/src/applications/modelTest/main.cpp(26): error: Failed
unexpected error messages
[ FAILED ] foo_test.does_not_throw (1 ms)
[----------] 1 test from foo_test (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (3 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] foo_test.does_not_throw
1 FAILED TEST
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With