mirror of https://github.com/google/googletest.git
Merge 3c4dd13cba into 283c17563f
This commit is contained in:
commit
aa7f7f919f
|
|
@ -488,6 +488,56 @@ nice mocks (not yet the default) most of the time, use naggy mocks (the current
|
|||
default) when developing or debugging tests, and use strict mocks only as the
|
||||
last resort.
|
||||
|
||||
### Requiring NiceMock or StrictMock {#RequireNiceOrStrict}
|
||||
|
||||
Large projects often want to ban naggy (default) mocks because warnings are easy
|
||||
to miss and hard to interpret. gMock supports an opt-in compile definition that
|
||||
forces an explicit choice between nice and strict behavior
|
||||
([issue #4882](https://github.com/google/googletest/issues/4882)):
|
||||
|
||||
```
|
||||
-DGOOGLEMOCK_REQUIRE_STRICT_OR_NICE=1
|
||||
```
|
||||
|
||||
or equivalently:
|
||||
|
||||
```
|
||||
-DGMOCK_FORCE_EXPLICIT_MOCK_KIND=1
|
||||
```
|
||||
|
||||
With that define set in a translation unit:
|
||||
|
||||
* `NiceMock<MockFoo>` and `StrictMock<MockFoo>` work as usual.
|
||||
* `NaggyMock<MockFoo>` fails to compile.
|
||||
* A bare `MockFoo` fails at the first `ON_CALL` / `EXPECT_CALL` or mock-method
|
||||
call unless the mock class declares a default:
|
||||
|
||||
```cpp
|
||||
class MockFoo : public Foo {
|
||||
public:
|
||||
DEFAULT_TO_STRICT(); // or DEFAULT_TO_NICE();
|
||||
|
||||
MOCK_METHOD(void, DoFoo, (), (override));
|
||||
};
|
||||
```
|
||||
|
||||
`DEFAULT_TO_NICE()` / `DEFAULT_TO_STRICT()` also work without the define: they
|
||||
make a bare `MockFoo` behave like `NiceMock` / `StrictMock`.
|
||||
|
||||
Upgrade path for existing codebases:
|
||||
|
||||
```cpp
|
||||
#define TODO_CHOOSE_NICE_OR_STRICT() DEFAULT_TO_NICE()
|
||||
```
|
||||
|
||||
Add `TODO_CHOOSE_NICE_OR_STRICT();` to every mock class, then enable
|
||||
`-DGOOGLEMOCK_REQUIRE_STRICT_OR_NICE=1`, then gradually replace the TODOs with
|
||||
real choices (or wrap instances in `NiceMock` / `StrictMock`).
|
||||
|
||||
The define is header-only and does not change the gMock library ABI; only
|
||||
translation units compiled with it are affected. Subprojects can keep building
|
||||
without the define.
|
||||
|
||||
### Simplifying the Interface without Breaking Existing Code {#SimplerInterfaces}
|
||||
|
||||
Sometimes a method has a long list of arguments that is mostly uninteresting.
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ if (gmock_build_tests)
|
|||
cxx_test(gmock-matchers-misc_test gmock_main)
|
||||
cxx_test(gmock-more-actions_test gmock_main)
|
||||
cxx_test(gmock-nice-strict_test gmock_main)
|
||||
cxx_test(gmock-require-strict-or-nice_test gmock_main)
|
||||
cxx_test(gmock-port_test gmock_main)
|
||||
cxx_test(gmock-spec-builders_test gmock_main)
|
||||
cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc)
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ using internal::FunctionMocker;
|
|||
GMOCK_PP_IF(_Final, final, ) { \
|
||||
GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||
.SetOwnerAndName(this, #_MethodName); \
|
||||
::testing::internal::EnforceNiceOrStrictMockKind(this); \
|
||||
return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||
.Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \
|
||||
} \
|
||||
|
|
@ -193,6 +194,7 @@ using internal::FunctionMocker;
|
|||
GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \
|
||||
GMOCK_PP_IF(_Constness, const, ) _RefSpec { \
|
||||
GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \
|
||||
::testing::internal::EnforceNiceOrStrictMockKind(this); \
|
||||
return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||
.With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \
|
||||
} \
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Implements class templates NiceMock, NaggyMock, and StrictMock.
|
||||
// Implements class templates NiceMock, NaggyMock, and StrictMock, and the
|
||||
// DEFAULT_TO_NICE() / DEFAULT_TO_STRICT() macros (issue #4882).
|
||||
//
|
||||
// Given a mock class MockFoo that is created using Google Mock,
|
||||
// NiceMock<MockFoo> is a subclass of MockFoo that allows
|
||||
|
|
@ -44,6 +45,12 @@
|
|||
// stop behaving like NaggyMock<MockFoo> and start behaving like
|
||||
// NiceMock<MockFoo>.
|
||||
//
|
||||
// DEFAULT_TO_NICE() / DEFAULT_TO_STRICT() may be placed in a mock class
|
||||
// to select nice/strict behavior for bare instances of that class.
|
||||
// With -DGOOGLEMOCK_REQUIRE_STRICT_OR_NICE=1 (or
|
||||
// -DGMOCK_FORCE_EXPLICIT_MOCK_KIND=1), naggy mocks are rejected: use a
|
||||
// NiceMock/StrictMock wrapper or one of those macros.
|
||||
//
|
||||
// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of
|
||||
// their respective base class. Therefore you can write
|
||||
// NiceMock<MockFoo>(5, "a") to construct a nice mock where MockFoo
|
||||
|
|
@ -145,6 +152,28 @@ class [[nodiscard]] StrictMockImpl {
|
|||
|
||||
} // namespace internal
|
||||
|
||||
// Declares that an uninteresting call on this mock class should be allowed
|
||||
// (nice). Place in a **public** section of the mock class:
|
||||
//
|
||||
// class MockFoo : public Foo {
|
||||
// public:
|
||||
// DEFAULT_TO_NICE();
|
||||
// MOCK_METHOD(void, DoFoo, (), (override));
|
||||
// };
|
||||
//
|
||||
// When GOOGLEMOCK_REQUIRE_STRICT_OR_NICE / GMOCK_FORCE_EXPLICIT_MOCK_KIND is
|
||||
// enabled, either this macro, DEFAULT_TO_STRICT(), or a NiceMock/StrictMock
|
||||
// wrapper is required (issue #4882).
|
||||
#define DEFAULT_TO_NICE() \
|
||||
::testing::internal::DefaultMockKindInstaller<::testing::internal::kAllow> \
|
||||
gmock_explicit_mock_kind_installer_
|
||||
|
||||
// Declares that an uninteresting call on this mock class should fail (strict).
|
||||
// Place in a **public** section of the mock class.
|
||||
#define DEFAULT_TO_STRICT() \
|
||||
::testing::internal::DefaultMockKindInstaller<::testing::internal::kFail> \
|
||||
gmock_explicit_mock_kind_installer_
|
||||
|
||||
template <class MockClass>
|
||||
class [[nodiscard]] GTEST_INTERNAL_EMPTY_BASE_CLASS NiceMock
|
||||
: private internal::NiceMockImpl<MockClass>,
|
||||
|
|
@ -195,6 +224,12 @@ class [[nodiscard]] GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock
|
|||
"strictness modifier. See "
|
||||
"https://google.github.io/googletest/"
|
||||
"gmock_cook_book.html#NiceStrictNaggy");
|
||||
static_assert(
|
||||
!GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE,
|
||||
"NaggyMock is disabled when GOOGLEMOCK_REQUIRE_STRICT_OR_NICE or "
|
||||
"GMOCK_FORCE_EXPLICIT_MOCK_KIND is enabled; use NiceMock, StrictMock, "
|
||||
"DEFAULT_TO_NICE(), or DEFAULT_TO_STRICT() instead "
|
||||
"(https://github.com/google/googletest/issues/4882)");
|
||||
|
||||
public:
|
||||
NaggyMock() : MockClass() {
|
||||
|
|
|
|||
|
|
@ -358,6 +358,12 @@ enum CallReaction {
|
|||
kFail,
|
||||
};
|
||||
|
||||
// Installs DEFAULT_TO_NICE / DEFAULT_TO_STRICT call reactions (see
|
||||
// gmock-nice-strict.h). Friended by Mock so it can call the private
|
||||
// Allow/Fail/Unregister APIs.
|
||||
template <CallReaction kReaction>
|
||||
class DefaultMockKindInstaller;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Utilities for manipulating mock objects.
|
||||
|
|
@ -406,6 +412,8 @@ class GTEST_API_ Mock {
|
|||
friend class internal::NaggyMockImpl;
|
||||
template <typename MockClass>
|
||||
friend class internal::StrictMockImpl;
|
||||
template <internal::CallReaction kReaction>
|
||||
friend class internal::DefaultMockKindInstaller;
|
||||
|
||||
// Tells Google Mock to allow uninteresting calls on the given mock
|
||||
// object.
|
||||
|
|
@ -462,6 +470,84 @@ class GTEST_API_ Mock {
|
|||
GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex);
|
||||
}; // class Mock
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Used by DEFAULT_TO_NICE() / DEFAULT_TO_STRICT() to set the uninteresting-call
|
||||
// reaction for a bare mock instance and clear it on destruction.
|
||||
template <CallReaction kReaction>
|
||||
class DefaultMockKindInstaller {
|
||||
public:
|
||||
DefaultMockKindInstaller() = default;
|
||||
~DefaultMockKindInstaller() {
|
||||
if (mock_obj_ != 0) {
|
||||
Mock::UnregisterCallReaction(mock_obj_);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultMockKindInstaller(const DefaultMockKindInstaller&) = delete;
|
||||
DefaultMockKindInstaller& operator=(const DefaultMockKindInstaller&) = delete;
|
||||
|
||||
void EnsureInstalled(const void* mock_obj) const {
|
||||
if (mock_obj_ != 0) {
|
||||
return;
|
||||
}
|
||||
mock_obj_ = reinterpret_cast<uintptr_t>(mock_obj);
|
||||
if constexpr (kReaction == kAllow) {
|
||||
Mock::AllowUninterestingCalls(mock_obj_);
|
||||
} else if constexpr (kReaction == kFail) {
|
||||
Mock::FailUninterestingCalls(mock_obj_);
|
||||
} else {
|
||||
Mock::WarnUninterestingCalls(mock_obj_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable uintptr_t mock_obj_ = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct HasDefaultMockKindInstaller : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasDefaultMockKindInstaller<
|
||||
T, std::void_t<decltype(std::declval<T&>().gmock_explicit_mock_kind_installer_)>>
|
||||
: std::true_type {};
|
||||
|
||||
// Called from MOCK_METHOD on ON_CALL/EXPECT_CALL and on each mock invocation.
|
||||
// Installs DEFAULT_TO_* reactions when present. When
|
||||
// GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE is enabled, also rejects naggy/bare
|
||||
// mocks (NiceMock/StrictMock wrappers and DEFAULT_TO_* are allowed).
|
||||
template <typename MockT>
|
||||
void EnforceNiceOrStrictMockKind(const MockT* mock) {
|
||||
if constexpr (HasDefaultMockKindInstaller<MockT>::value) {
|
||||
void* const mock_obj =
|
||||
const_cast<void*>(static_cast<const void*>(mock));
|
||||
// NiceMock/StrictMock register their reaction in a base before MockClass
|
||||
// runs; prefer that over DEFAULT_TO_* on the mock class.
|
||||
if (Mock::IsNice(mock_obj) || Mock::IsStrict(mock_obj)) {
|
||||
return;
|
||||
}
|
||||
mock->gmock_explicit_mock_kind_installer_.EnsureInstalled(mock);
|
||||
return;
|
||||
}
|
||||
#if GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE
|
||||
void* const mock_obj =
|
||||
const_cast<void*>(static_cast<const void*>(mock));
|
||||
if (!Mock::IsNice(mock_obj) && !Mock::IsStrict(mock_obj)) {
|
||||
Assert(false, __FILE__, __LINE__,
|
||||
"When GOOGLEMOCK_REQUIRE_STRICT_OR_NICE or "
|
||||
"GMOCK_FORCE_EXPLICIT_MOCK_KIND is enabled, mocks must be wrapped "
|
||||
"in NiceMock<> or StrictMock<>, or the mock class must declare "
|
||||
"DEFAULT_TO_NICE() or DEFAULT_TO_STRICT(). See "
|
||||
"https://github.com/google/googletest/issues/4882");
|
||||
}
|
||||
#else
|
||||
(void)mock;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// An abstract handle of an expectation. Useful in the .After()
|
||||
// clause of EXPECT_CALL() for setting the (partial) order of
|
||||
// expectations. The syntax:
|
||||
|
|
|
|||
|
|
@ -57,6 +57,26 @@
|
|||
#include "gmock/internal/custom/gmock-port.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// When set to a non-zero value, gMock rejects naggy (default) mocks: each mock
|
||||
// must be wrapped in NiceMock/StrictMock, or the mock class must declare
|
||||
// DEFAULT_TO_NICE() / DEFAULT_TO_STRICT() (see gmock-nice-strict.h).
|
||||
// Enforcement is header-only and does not change the gMock library ABI; only
|
||||
// TUs compiled with the macro are affected. Issue #4882.
|
||||
//
|
||||
// Enable with either:
|
||||
// -DGOOGLEMOCK_REQUIRE_STRICT_OR_NICE=1
|
||||
// -DGMOCK_FORCE_EXPLICIT_MOCK_KIND=1
|
||||
#if !defined(GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE)
|
||||
#if (defined(GOOGLEMOCK_REQUIRE_STRICT_OR_NICE) && \
|
||||
GOOGLEMOCK_REQUIRE_STRICT_OR_NICE) || \
|
||||
(defined(GMOCK_FORCE_EXPLICIT_MOCK_KIND) && \
|
||||
GMOCK_FORCE_EXPLICIT_MOCK_KIND)
|
||||
#define GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE 1
|
||||
#else
|
||||
#define GMOCK_INTERNAL_REQUIRE_STRICT_OR_NICE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(GTEST_HAS_ABSL) && !defined(GTEST_NO_ABSL_FLAGS)
|
||||
#include "absl/flags/declare.h"
|
||||
#include "absl/flags/flag.h"
|
||||
|
|
|
|||
|
|
@ -537,5 +537,51 @@ TEST(StrictMockTest, IsNaggy_IsNice_IsStrict) {
|
|||
EXPECT_TRUE(Mock::IsStrict(&strict_foo));
|
||||
}
|
||||
|
||||
class MockFooDefaultNice {
|
||||
public:
|
||||
DEFAULT_TO_NICE();
|
||||
MOCK_METHOD(void, DoThis, ());
|
||||
};
|
||||
|
||||
class MockFooDefaultStrict {
|
||||
public:
|
||||
DEFAULT_TO_STRICT();
|
||||
MOCK_METHOD(void, DoThis, ());
|
||||
};
|
||||
|
||||
// DEFAULT_TO_NICE() makes a bare mock behave like NiceMock.
|
||||
TEST(DefaultToNiceTest, IsNice) {
|
||||
MockFooDefaultNice mock;
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
mock.DoThis();
|
||||
EXPECT_TRUE(Mock::IsNice(&mock));
|
||||
EXPECT_FALSE(Mock::IsStrict(&mock));
|
||||
EXPECT_FALSE(Mock::IsNaggy(&mock));
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STREAM_REDIRECTION
|
||||
TEST(DefaultToNiceTest, NoWarningForUninterestingCall) {
|
||||
MockFooDefaultNice mock;
|
||||
CaptureStdout();
|
||||
mock.DoThis();
|
||||
EXPECT_EQ("", GetCapturedStdout());
|
||||
}
|
||||
#endif
|
||||
|
||||
// DEFAULT_TO_STRICT() makes a bare mock behave like StrictMock.
|
||||
TEST(DefaultToStrictTest, IsStrict) {
|
||||
MockFooDefaultStrict mock;
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
mock.DoThis();
|
||||
EXPECT_TRUE(Mock::IsStrict(&mock));
|
||||
EXPECT_FALSE(Mock::IsNice(&mock));
|
||||
EXPECT_FALSE(Mock::IsNaggy(&mock));
|
||||
}
|
||||
|
||||
TEST(DefaultToStrictTest, UninterestingCallFails) {
|
||||
MockFooDefaultStrict mock;
|
||||
EXPECT_NONFATAL_FAILURE(mock.DoThis(), "Uninteresting mock function call");
|
||||
}
|
||||
|
||||
} // namespace gmock_nice_strict_test
|
||||
} // namespace testing
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2025, 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.
|
||||
|
||||
// Tests GOOGLEMOCK_REQUIRE_STRICT_OR_NICE / GMOCK_FORCE_EXPLICIT_MOCK_KIND
|
||||
// (https://github.com/google/googletest/issues/4882).
|
||||
|
||||
#define GOOGLEMOCK_REQUIRE_STRICT_OR_NICE 1
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::StrictMock;
|
||||
|
||||
class MockFoo {
|
||||
public:
|
||||
MOCK_METHOD(void, DoThis, ());
|
||||
};
|
||||
|
||||
class MockFooDefaultNice {
|
||||
public:
|
||||
DEFAULT_TO_NICE();
|
||||
MOCK_METHOD(void, DoThis, ());
|
||||
};
|
||||
|
||||
class MockFooDefaultStrict {
|
||||
public:
|
||||
DEFAULT_TO_STRICT();
|
||||
MOCK_METHOD(void, DoThis, ());
|
||||
};
|
||||
|
||||
TEST(RequireStrictOrNiceTest, BareMockFailsOnCall) {
|
||||
MockFoo mock;
|
||||
EXPECT_FATAL_FAILURE(mock.DoThis(), "GOOGLEMOCK_REQUIRE_STRICT_OR_NICE");
|
||||
}
|
||||
|
||||
TEST(RequireStrictOrNiceTest, BareMockFailsOnExpectCall) {
|
||||
MockFoo mock;
|
||||
EXPECT_FATAL_FAILURE(
|
||||
{
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
},
|
||||
"GOOGLEMOCK_REQUIRE_STRICT_OR_NICE");
|
||||
}
|
||||
|
||||
TEST(RequireStrictOrNiceTest, NiceMockAllowed) {
|
||||
NiceMock<MockFoo> mock;
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
mock.DoThis();
|
||||
EXPECT_TRUE(testing::Mock::IsNice(&mock));
|
||||
}
|
||||
|
||||
TEST(RequireStrictOrNiceTest, StrictMockAllowed) {
|
||||
StrictMock<MockFoo> mock;
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
mock.DoThis();
|
||||
EXPECT_TRUE(testing::Mock::IsStrict(&mock));
|
||||
}
|
||||
|
||||
TEST(RequireStrictOrNiceTest, DefaultToNiceAllowed) {
|
||||
MockFooDefaultNice mock;
|
||||
mock.DoThis(); // uninteresting, but nice
|
||||
EXPECT_TRUE(testing::Mock::IsNice(&mock));
|
||||
}
|
||||
|
||||
TEST(RequireStrictOrNiceTest, DefaultToStrictAllowed) {
|
||||
MockFooDefaultStrict mock;
|
||||
EXPECT_CALL(mock, DoThis());
|
||||
mock.DoThis();
|
||||
EXPECT_TRUE(testing::Mock::IsStrict(&mock));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Loading…
Reference in New Issue