diff --git a/docs/release_notes.adoc b/docs/release_notes.adoc index 6867c79fd4..9afc11460b 100644 --- a/docs/release_notes.adoc +++ b/docs/release_notes.adoc @@ -14,6 +14,7 @@ include::include.adoc[] * Fix argument mismatch descriptions for varargs methods by expanding varargs instead of reporting `` spockPull:2315[] * Fix Pattern flags being dropped when `java.util.regex.Pattern` instances are used in Spock regex conditions spockIssue:2298[] +* Fix `MockitoMockMaker` throws NPE on null object spockIssue:2337[] == 2.4 (2025-12-11) diff --git a/spock-core/src/main/java/org/spockframework/mock/runtime/IMockMaker.java b/spock-core/src/main/java/org/spockframework/mock/runtime/IMockMaker.java index 66fa3e10b3..3df0653e0a 100644 --- a/spock-core/src/main/java/org/spockframework/mock/runtime/IMockMaker.java +++ b/spock-core/src/main/java/org/spockframework/mock/runtime/IMockMaker.java @@ -125,6 +125,7 @@ default IStaticMock makeStaticMock(IMockCreationSettings settings) throws Cannot * @param object a potential mock object * @return information about the mock object or {@code null} */ + @Nullable default IMockObject asMockOrNull(Object object) { return null; } diff --git a/spock-core/src/main/java/org/spockframework/mock/runtime/MockMakerRegistry.java b/spock-core/src/main/java/org/spockframework/mock/runtime/MockMakerRegistry.java index dc9360bb9a..d829d7fbb3 100644 --- a/spock-core/src/main/java/org/spockframework/mock/runtime/MockMakerRegistry.java +++ b/spock-core/src/main/java/org/spockframework/mock/runtime/MockMakerRegistry.java @@ -22,7 +22,6 @@ import org.spockframework.mock.ISpockMockObject; import org.spockframework.mock.runtime.IMockMaker.IStaticMock; import org.spockframework.mock.runtime.IMockMaker.MockMakerCapability; -import org.spockframework.runtime.GroovyRuntimeUtil; import org.spockframework.util.InternalSpockError; import org.spockframework.util.Nullable; import org.spockframework.util.ThreadSafe; @@ -182,7 +181,11 @@ private static void checkForStaticMockUsageWithClosure(IMockCreationSettings set * @param object a mock object * @return information about the mock object */ - public IMockObject asMockOrNull(Object object) { + @Nullable + public IMockObject asMockOrNull(@Nullable Object object) { + if (object == null) { + return null; + } if (object instanceof ISpockMockObject) { return ((ISpockMockObject) object).$spock_get(); } diff --git a/spock-core/src/main/java/org/spockframework/mock/runtime/mockito/MockitoMockMaker.java b/spock-core/src/main/java/org/spockframework/mock/runtime/mockito/MockitoMockMaker.java index be581fa754..1506bba99c 100644 --- a/spock-core/src/main/java/org/spockframework/mock/runtime/mockito/MockitoMockMaker.java +++ b/spock-core/src/main/java/org/spockframework/mock/runtime/mockito/MockitoMockMaker.java @@ -19,6 +19,7 @@ import org.spockframework.mock.CannotCreateMockException; import org.spockframework.mock.IMockObject; import org.spockframework.mock.runtime.IMockMaker; +import org.spockframework.util.Nullable; import org.spockframework.util.ReflectionUtil; import org.spockframework.util.ThreadSafe; import spock.mock.MockMakerId; @@ -69,8 +70,9 @@ public int getPriority() { } @Override - public IMockObject asMockOrNull(Object object) { - if (impl == null) { + @Nullable + public IMockObject asMockOrNull(@Nullable Object object) { + if (impl == null || object == null) { return null; } return impl.asMockOrNull(object); diff --git a/spock-specs/src/test/groovy/org/spockframework/mock/runtime/mockito/MockitoMockMakerSpec.groovy b/spock-specs/src/test/groovy/org/spockframework/mock/runtime/mockito/MockitoMockMakerSpec.groovy index b120bb6aed..006b32968c 100644 --- a/spock-specs/src/test/groovy/org/spockframework/mock/runtime/mockito/MockitoMockMakerSpec.groovy +++ b/spock-specs/src/test/groovy/org/spockframework/mock/runtime/mockito/MockitoMockMakerSpec.groovy @@ -45,6 +45,14 @@ class MockitoMockMakerSpec extends Specification { mockito.toString() == "$ID default mock maker settings" } + def "MockitoMockMaker.asMockOrNull() on null returns null"() { + given: + def maker = new MockitoMockMaker() + + expect: + maker.asMockOrNull(null) == null + } + def "Verify ID and IMockMakerSettings with Mockito settings"() { when: def set = mockito {} @@ -507,6 +515,19 @@ Can not mock final classes with the following settings : additionalInterfaceClass.isInstance(m) mockUtil.isMock(m) } + + @Issue("https://github.com/spockframework/spock/issues/2337") + def "NPE when stubbing method on null object"() { + given: + Object nullObj = null + + when: + //Issue #2337: MockitoMockMaker passes null to Mockito's getHandler() throws NPE + nullObj.toString() >> "" + + then: + noExceptionThrown() + } } class AccessProtectedBaseClass {