Skip to content

Commit

Permalink
Fix nested static mock stubs (#2685)
Browse files Browse the repository at this point in the history
This also fixes the `WrongTypeOfReturnValue` issue for spy stubs.

Fixes #2616

Co-authored-by: yushouqiu <yushouqiu@xiaomi.com>
  • Loading branch information
fishautumn and fishautumn committed Jun 18, 2022
1 parent 512ee39 commit 807b121
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 26 deletions.
31 changes: 19 additions & 12 deletions src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
Expand Up @@ -107,18 +107,25 @@ public Object handle(Invocation invocation) throws Throwable {
mockingProgress().reportOngoingStubbing(ongoingStubbing);
}
} else {
Object ret = mockSettings.getDefaultAnswer().answer(invocation);
DefaultAnswerValidator.validateReturnValueFor(invocation, ret);

// Mockito uses it to redo setting invocation for potential stubbing in case of partial
// mocks / spies.
// Without it, the real method inside 'when' might have delegated to other self method
// and overwrite the intended stubbed method with a different one.
// This means we would be stubbing a wrong method.
// Typically this would led to runtime exception that validates return type with stubbed
// method signature.
invocationContainer.resetInvocationForPotentialStubbing(invocationMatcher);
return ret;
try {
Object ret = mockSettings.getDefaultAnswer().answer(invocation);
DefaultAnswerValidator.validateReturnValueFor(invocation, ret);

return ret;
} finally {
// Mockito uses it to redo setting invocation for potential stubbing in case of
// partial
// mocks / spies.
// Without it, the real method inside 'when' might have delegated to other self
// method
// and overwrite the intended stubbed method with a different one.
// This means we would be stubbing a wrong method.
// Typically this would led to runtime exception that validates return type with
// stubbed
// method signature.
invocationContainer.resetInvocationForPotentialStubbing(invocationMatcher);
mockingProgress().reportOngoingStubbing(ongoingStubbing);
}
}
}

Expand Down
Expand Up @@ -2,32 +2,23 @@
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitousage.misuse;
package org.mockitousage.spies;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.*;

import org.junit.Test;
import org.mockito.exceptions.misusing.WrongTypeOfReturnValue;

public class SpyStubbingMisuseTest {
public class SpyAsDefaultMockUsageTest {

@Test
public void nestedWhenTest() {
Strategy mfoo = mock(Strategy.class);
Sampler mpoo = mock(Sampler.class);
Producer out = spy(new Producer(mfoo));

try {
when(out.produce()).thenReturn(mpoo);
fail();
} catch (WrongTypeOfReturnValue e) {
assertThat(e.getMessage())
.contains("spy")
.contains("syntax")
.contains("doReturn|Throw");
}
when(out.produce()).thenReturn(mpoo);
assertSame(mpoo, out.produce());
}

public class Sample {}
Expand Down
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitoinline.bugs;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.mockito.MockedStatic;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.mockStatic;

public class OngoingStubShiftTest {

private static class StaticInt {
static int getInt() {
return 1;
}
}

private static class StaticStr {
static String getStr() {
return Integer.toString(StaticInt.getInt());
}
}

@Test
public void keep_ongoing_stub_when_spy() {
try (MockedStatic<StaticInt> mockInt = mockStatic(StaticInt.class);
MockedStatic<StaticStr> mockStr = mockStatic(StaticStr.class, CALLS_REAL_METHODS)) {

mockStr.when(StaticStr::getStr).thenReturn("1");
assertEquals("1", StaticStr.getStr());
}
}

private static class StaticWithException {
static String getString() {
return Integer.toString(getInt());
}

static int getInt() {
throw new NullPointerException();
}
}

@Test
public void keep_ongoing_stub_when_exception() {
try (MockedStatic<StaticWithException> mock = mockStatic(StaticWithException.class, CALLS_REAL_METHODS)) {
mock.when(StaticWithException::getString).thenReturn("1");
assertEquals("1", StaticWithException.getString());
}
}
}

0 comments on commit 807b121

Please sign in to comment.