org.mockito.internal.handler.MockHandlerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mockito-core Show documentation
Show all versions of mockito-core Show documentation
Mockito mock objects library core API and implementation
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.handler;
import static org.mockito.internal.listeners.StubbingLookupNotifier.notifyStubbedAnswerLookup;
import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.internal.invocation.InvocationMatcher;
import org.mockito.internal.invocation.MatchersBinder;
import org.mockito.internal.stubbing.InvocationContainerImpl;
import org.mockito.internal.stubbing.OngoingStubbingImpl;
import org.mockito.internal.stubbing.StubbedInvocationMatcher;
import org.mockito.internal.stubbing.answers.DefaultAnswerValidator;
import org.mockito.internal.util.MockUtil;
import org.mockito.internal.verification.MockAwareVerificationMode;
import org.mockito.internal.verification.VerificationDataImpl;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.InvocationContainer;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
import org.mockito.verification.VerificationMode;
/**
* Invocation handler set on mock objects.
*
* @param type of mock object to handle
*/
public class MockHandlerImpl implements MockHandler {
private static final long serialVersionUID = -2917871070982574165L;
InvocationContainerImpl invocationContainer;
MatchersBinder matchersBinder = new MatchersBinder();
private final MockCreationSettings mockSettings;
public MockHandlerImpl(MockCreationSettings mockSettings) {
this.mockSettings = mockSettings;
this.matchersBinder = new MatchersBinder();
this.invocationContainer = new InvocationContainerImpl(mockSettings);
}
@Override
public Object handle(Invocation invocation) throws Throwable {
if (invocationContainer.hasAnswersForStubbing()) {
// stubbing voids with doThrow() or doAnswer() style
InvocationMatcher invocationMatcher =
matchersBinder.bindMatchers(
mockingProgress().getArgumentMatcherStorage(), invocation);
invocationContainer.setMethodForStubbing(invocationMatcher);
return null;
}
VerificationMode verificationMode = mockingProgress().pullVerificationMode();
InvocationMatcher invocationMatcher =
matchersBinder.bindMatchers(
mockingProgress().getArgumentMatcherStorage(), invocation);
mockingProgress().validateState();
// if verificationMode is not null then someone is doing verify()
if (verificationMode != null) {
// We need to check if verification was started on the correct mock
// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
if (MockUtil.areSameMocks(
((MockAwareVerificationMode) verificationMode).getMock(),
invocation.getMock())) {
VerificationDataImpl data =
new VerificationDataImpl(invocationContainer, invocationMatcher);
verificationMode.verify(data);
return null;
} else {
// this means there is an invocation on a different mock. Re-adding verification
// mode
// - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
mockingProgress().verificationStarted(verificationMode);
}
}
// prepare invocation for stubbing
invocationContainer.setInvocationForPotentialStubbing(invocationMatcher);
OngoingStubbingImpl ongoingStubbing = new OngoingStubbingImpl(invocationContainer);
mockingProgress().reportOngoingStubbing(ongoingStubbing);
// look for existing answer for this invocation
StubbedInvocationMatcher stubbing = invocationContainer.findAnswerFor(invocation);
// TODO #793 - when completed, we should be able to get rid of the casting below
notifyStubbedAnswerLookup(
invocation,
stubbing,
invocationContainer.getStubbingsAscending(),
(CreationSettings) mockSettings);
if (stubbing != null) {
stubbing.captureArgumentsFrom(invocation);
try {
return stubbing.answer(invocation);
} finally {
// Needed so that we correctly isolate stubbings in some scenarios
// see MockitoStubbedCallInAnswerTest or issue #1279
mockingProgress().reportOngoingStubbing(ongoingStubbing);
}
} else {
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);
}
}
}
@Override
public MockCreationSettings getMockSettings() {
return mockSettings;
}
@Override
public InvocationContainer getInvocationContainer() {
return invocationContainer;
}
}