mirror of
https://github.com/google/googletest.git
synced 2024-12-26 17:41:03 +08:00
Add ability to throw from ASSERT
while not losing benefits of EXPECT, and not killing the whole test, as with --gtest_throw_on_failure. 183822976
This commit is contained in:
parent
ea31cb15f0
commit
092d088533
@ -872,13 +872,33 @@ TEST(FooTest, Bar) {
|
||||
}
|
||||
```
|
||||
|
||||
Since we don't use exceptions, it is technically impossible to
|
||||
implement the intended behavior here. To alleviate this, Google Test
|
||||
provides two solutions. You could use either the
|
||||
`(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the
|
||||
`HasFatalFailure()` function. They are described in the following two
|
||||
To alleviate this, gUnit provides three different solutions. You could use
|
||||
either exceptions, the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the
|
||||
`HasFatalFailure()` function. They are described in the following two
|
||||
subsections.
|
||||
|
||||
#### Asserting on Subroutines with an exception
|
||||
|
||||
The following code can turn ASSERT-failure into an exception:
|
||||
|
||||
```c++
|
||||
class ThrowListener : public testing::EmptyTestEventListener {
|
||||
void OnTestPartResult(const testing::TestPartResult& result) override {
|
||||
if (result.type() == testing::TestPartResult::kFatalFailure) {
|
||||
throw testing::AssertionException(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
int main(int argc, char** argv) {
|
||||
...
|
||||
testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
```
|
||||
|
||||
This listener should be added after other listeners if you have any, otherwise
|
||||
they won't see failed `OnTestPartResult`.
|
||||
|
||||
### Asserting on Subroutines ###
|
||||
|
||||
As shown above, if your test calls a subroutine that has an `ASSERT_*`
|
||||
|
@ -138,7 +138,7 @@ GTEST_DECLARE_int32_(stack_trace_depth);
|
||||
|
||||
// When this flag is specified, a failed assertion will throw an
|
||||
// exception if exceptions are enabled, or exit the program with a
|
||||
// non-zero code otherwise.
|
||||
// non-zero code otherwise. For use with an external test framework.
|
||||
GTEST_DECLARE_bool_(throw_on_failure);
|
||||
|
||||
// When this flag is set with a "host:port" string, on supported
|
||||
@ -1004,6 +1004,18 @@ class Environment {
|
||||
virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
|
||||
};
|
||||
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
|
||||
// Exception which can be thrown from TestEventListener::OnTestPartResult.
|
||||
class GTEST_API_ AssertionException
|
||||
: public internal::GoogleTestFailureException {
|
||||
public:
|
||||
explicit AssertionException(const TestPartResult& result)
|
||||
: GoogleTestFailureException(result) {}
|
||||
};
|
||||
|
||||
#endif // GTEST_HAS_EXCEPTIONS
|
||||
|
||||
// The interface for tracing execution of tests. The methods are organized in
|
||||
// the order the corresponding events are fired.
|
||||
class TestEventListener {
|
||||
@ -1032,6 +1044,8 @@ class TestEventListener {
|
||||
virtual void OnTestStart(const TestInfo& test_info) = 0;
|
||||
|
||||
// Fired after a failed assertion or a SUCCEED() invocation.
|
||||
// If you want to throw an exception from this function to skip to the next
|
||||
// TEST, it must be AssertionException defined above, or inherited from it.
|
||||
virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
|
||||
|
||||
// Fired after the test ends.
|
||||
|
@ -293,7 +293,7 @@ GTEST_DEFINE_bool_(
|
||||
internal::BoolFromGTestEnv("throw_on_failure", false),
|
||||
"When this flag is specified, a failed assertion will throw an exception "
|
||||
"if exceptions are enabled or exit the program with a non-zero code "
|
||||
"otherwise.");
|
||||
"otherwise. For use with an external test framework.");
|
||||
|
||||
#if GTEST_USE_OWN_FLAGFILE_FLAG_
|
||||
GTEST_DEFINE_string_(
|
||||
@ -2435,6 +2435,8 @@ Result HandleExceptionsInMethodIfSupported(
|
||||
#if GTEST_HAS_EXCEPTIONS
|
||||
try {
|
||||
return HandleSehExceptionsInMethodIfSupported(object, method, location);
|
||||
} catch (const AssertionException&) { // NOLINT
|
||||
// This failure was reported already.
|
||||
} catch (const internal::GoogleTestFailureException&) { // NOLINT
|
||||
// This exception type can only be thrown by a failed Google
|
||||
// Test assertion with the intention of letting another testing
|
||||
@ -5201,7 +5203,8 @@ static const char kColorEncodedHelpMessage[] =
|
||||
" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
|
||||
" Turn assertion failures into debugger break-points.\n"
|
||||
" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
|
||||
" Turn assertion failures into C++ exceptions.\n"
|
||||
" Turn assertion failures into C++ exceptions for use by an external\n"
|
||||
" test framework.\n"
|
||||
" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
|
||||
" Do not report exceptions as test failures. Instead, allow them\n"
|
||||
" to crash the program or throw a pop-up (on Windows).\n"
|
||||
|
@ -219,6 +219,13 @@ py_test(
|
||||
deps = [":gtest_test_utils"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "gtest_assert_by_exception_test",
|
||||
size = "small",
|
||||
srcs = ["gtest_assert_by_exception_test.cc"],
|
||||
deps = ["//:gtest"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "gtest_throw_on_failure_test_",
|
||||
testonly = 1,
|
||||
|
119
googletest/test/gtest_assert_by_exception_test.cc
Normal file
119
googletest/test/gtest_assert_by_exception_test.cc
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright 2009, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Tests Google Test's assert-by-exception mode with exceptions enabled.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdexcept>
|
||||
|
||||
class ThrowListener : public testing::EmptyTestEventListener {
|
||||
void OnTestPartResult(const testing::TestPartResult& result) override {
|
||||
if (result.type() == testing::TestPartResult::kFatalFailure) {
|
||||
throw testing::AssertionException(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Prints the given failure message and exits the program with
|
||||
// non-zero. We use this instead of a Google Test assertion to
|
||||
// indicate a failure, as the latter is been tested and cannot be
|
||||
// relied on.
|
||||
void Fail(const char* msg) {
|
||||
printf("FAILURE: %s\n", msg);
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void AssertFalse() {
|
||||
ASSERT_EQ(2, 3) << "Expected failure";
|
||||
}
|
||||
|
||||
// Tests that an assertion failure throws a subclass of
|
||||
// std::runtime_error.
|
||||
TEST(Test, Test) {
|
||||
// A successful assertion shouldn't throw.
|
||||
try {
|
||||
EXPECT_EQ(3, 3);
|
||||
} catch(...) {
|
||||
Fail("A successful assertion wrongfully threw.");
|
||||
}
|
||||
|
||||
// A successful assertion shouldn't throw.
|
||||
try {
|
||||
EXPECT_EQ(3, 4);
|
||||
} catch(...) {
|
||||
Fail("A failed non-fatal assertion wrongfully threw.");
|
||||
}
|
||||
|
||||
// A failed assertion should throw.
|
||||
try {
|
||||
AssertFalse();
|
||||
} catch(const testing::AssertionException& e) {
|
||||
if (strstr(e.what(), "Expected failure") != NULL)
|
||||
throw;
|
||||
|
||||
printf("%s",
|
||||
"A failed assertion did throw an exception of the right type, "
|
||||
"but the message is incorrect. Instead of containing \"Expected "
|
||||
"failure\", it is:\n");
|
||||
Fail(e.what());
|
||||
} catch(...) {
|
||||
Fail("A failed assertion threw the wrong type of exception.");
|
||||
}
|
||||
Fail("A failed assertion should've thrown but didn't.");
|
||||
}
|
||||
|
||||
int kTestForContinuingTest = 0;
|
||||
|
||||
TEST(Test, Test2) {
|
||||
// FIXME(sokolov): how to force Test2 to be after Test?
|
||||
kTestForContinuingTest = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
|
||||
|
||||
int result = RUN_ALL_TESTS();
|
||||
if (result == 0) {
|
||||
printf("RUN_ALL_TESTS returned %d\n", result);
|
||||
Fail("Expected failure instead.");
|
||||
}
|
||||
|
||||
if (kTestForContinuingTest == 0) {
|
||||
Fail("Should have continued with other tests, but did not.");
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user