This commit is contained in:
Amelia Barnaby 2026-09-04 11:06:02 +02:00 committed by GitHub
commit aa7f7f919f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 343 additions and 1 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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)); \
} \

View File

@ -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() {

View File

@ -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:

View File

@ -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"

View File

@ -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

View File

@ -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