GoogleMock display more detailed debug info
Asked Answered
F

4

7

I'm using googlemock at work. We often use EXPECT_THROW, EXPECT_NO_THROW etc...

My question is how do you make googlemock output the exception details and maybe a stack trace when a function is wrapped in a EXPECT_NO_THROW, but actually throws an exception(ie code bug)?

The only output I get is that it threw an exception and failed the test...which is not useful for debugging the root cause.

Freightage answered 11/7, 2012 at 18:56 Comment(2)
This also effects me in GoogleTest. My custom My::Exception class has virtual inheritance from both std::exception and boost::exception, and google test still doesn't get any useful info out of my overriden what().Eisele
Given that Google itself doesn't use C++ exceptions, I'd be unsurprised by poor support in their libraries... :-(Eggnog
S
2

EXPECT_THROW, EXPECT_NO_THROW, etc. are really part of Google Test rather than Google Mock.

I don't know of any way to get further info on the exception other than hacking the gtest source. For std::exceptions only, the following change should at least output the exception's what() when an EXPECT_NO_THROW or ASSERT_NO_THROW fails.

In gtest/include/gtest/internal/gtest-internal.h, around line 1140, change the GTEST_TEST_NO_THROW_ macro to:

#define GTEST_TEST_NO_THROW_(statement, fail) \
  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  if (::testing::internal::AlwaysTrue()) { \
    try { \
      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
    } \
    catch (...) { \
      try { \
        std::exception_ptr exceptn_ptr(std::current_exception()); \
        std::rethrow_exception(exceptn_ptr); \
      } catch(const std::exception& exceptn) { \
        std::cerr << exceptn.what() << '\n'; \
      } \
      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
    } \
  } else \
    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
      fail("Expected: " #statement " doesn't throw an exception.\n" \
           "  Actual: it throws.")

You can obviously add more functionality here; catching custom exception types, formatting the failure message to include the exception info, etc.

Stepheniestephens answered 11/7, 2012 at 23:44 Comment(0)
S
1

You can also omit the assertion alltogether and let your test case throw an exception. So instead of asserting that f() does not throw:

ASSERT_NO_THROW(f());

you simply call the function:

f();

If it throws an exception, it will give you an output like this one:

C++ exception with description "something broke in f()" thrown in the test body.

This of course only works with ASSERT_NO_THROW, because the test case will terminate.

Shumpert answered 4/5, 2015 at 10:0 Comment(2)
This is what I do. As far as I can tell, there is no value to using ASSERT_NO_THROW, since both the throw or the assert will terminate the test case, but not the test suite, and the assert macro just masks the reason for the failure. EXPECT_NO_THROW could have some value, if for some reason you want the test case to continue running even though the expression threw an exception (but still wanted the test case to fail). I can't imagine a scenario where this would be true, but at least it results in different behavior from ASSERT_NO_THROW.Aerophobia
The value is two-fold: (1) it identifies which test file/line threw an unexpected exception, since you could have multiple places in the same test that could potentially throw an exception but shouldn't; and (2) if your ASSERT_NO_THROW() is used inside some function which itself might be within something that has try/catch around it for other reasons, then you still want the overall test to fail. For example if you create mocks which implement test assertions and they are given to normal/non-test objects that have try/catch because they do that for production.Barocchio
B
0

In general, GMock/GTest isn't in a position to do anything with the caught object. It can't just assume that your code threw a subclass of std::exception as much as you'd like it to, and C++ doesn't provide any means of saving stack traces when exceptions are raised, even if stack frames and debugging symbols are actually present in your binary.

But then, unit testing is really a technique for verification, and other tools must be your friend for diagnostics. Whether it's adding temporary logging (e.g. printf) or an interactive debugger such as gdb, there are better tools for the job.

Bakeman answered 4/5, 2015 at 12:2 Comment(0)
F
-1

I found it easiest to just run gdb on the unit test binaries. Luckily we compile all code with debug enabled =].

Freightage answered 12/7, 2012 at 15:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.