Test a specific exception type is thrown AND the exception has the right properties
I mostly second Lilshieste's answer but would add that you also should verify that the wrong exception type is not thrown:
#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();
}
A colleague came up with the solution by just re-throwing the exception.
The knack: no need of extra FAIL() statements, just the two EXPECT... calls that test the bits you actually want: the exception as such and its value.
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 );
}
Jeff Langr describes a good approach in his book, Modern C++ Programming with Test-Driven Development:
If your [testing] framework does not support a single-line declarative assert that ensures an exception is thrown, you can use the following structure in your test:
TEST(ATweet, RequiresUserNameToStartWithAnAtSign) { string invalidUser("notStartingWith@"); try { Tweet tweet("msg", invalidUser); FAIL(); } catch(const InvalidUserException& expected) {} }
[...] You might also need to use the try-catch structure if you must verify any postconditions after the exception is thrown. For example, you may want to verify the text associated with the thrown exception object.
TEST(ATweet, RequiresUserNameToStartWithAtSign) { string invalidUser("notStartingWith@"); try { Tweet tweet("msg", invalidUser); FAIL(); } catch(const InvalidUserException& expected) { ASSERT_STREQ("notStartingWith@", expected.what()); } }
(p.95)
This is the approach I've used, and have seen in practice elsewhere.
Edit: As has been pointed out by @MikeKinghan, this doesn't quite match the functionality provided by EXPECT_THROW
; the test doesn't fail if the wrong exception is thrown. An additional catch
clause could be added to address this:
catch(...) {
FAIL();
}