com.roscopeco.moxy.api.MoxyVoidStubber Maven / Gradle / Ivy
/*
* Moxy - Lean-and-mean mocking framework for Java with a fluent API.
*
* Copyright 2018 Ross Bamford
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.roscopeco.moxy.api;
import java.util.List;
import java.util.function.Consumer;
/**
* Special case stubber for void methods. Does not allow a return
* value to be set.
*
* Implementations of this are returned by the
* {@link MoxyEngine#when(com.roscopeco.moxy.api.InvocationRunnable)}
* method
*
* @author Ross Bamford <roscopeco AT gmail DOT com>
* @since 1.0
*/
public interface MoxyVoidStubber {
/**
* Stubs the mock invocation to throw the given Throwable
.
*
* Note that mocks may be stubbed to throw any throwable -
* checked or unchecked - irrespective of the method's throws
* clause. This should be used with caution as undeclared checked
* exceptions may cause undefined behaviour in callers.
*
* This method may be chained with other then...
methods,
* which will cause the mocked invocation to exhibit the chained
* behaviours, in order, upon multiple calls to the mock.
*
* See {@link MoxyStubber#thenReturn(Object)} for a example of chained stubbing.
*
* @param throwable The Throwable
to throw for matching invocations.
*
* @return this
, for ongoing stubbing.
*
* @since 1.0
*/
public MoxyVoidStubber thenThrow(Throwable throwable);
/**
* Instead of stubbing, have the mock call the real method instead.
*
* When this method is used to have mocks call their real methods,
* verification is unaffected. In other words, you may verify these
* mocks in the same way as any other.
*
* For obvious reasons, this will only work where the mocked method
* is not abstract
. If it is, an
* {@link InvalidStubbingException} will be thrown when the mock is invoked.
*
* This method may be chained with other then...
methods,
* which will cause the mocked invocation to exhibit the chained
* behaviours, in order, upon multiple calls to the mock.
*
* See {@link MoxyStubber#thenReturn(Object)} for a example of chained stubbing.
*
* @return this
, for ongoing stubbing.
*
* @since 1.0
*/
public MoxyVoidStubber thenCallRealMethod();
/**
* Have this method delegate calls to the first compatible method on
* the given object.
*
* When this is applied to a mocked method, all calls will be delegated
* to an appropriate method on the given object. That means the method
* will:
*
*
* - Not be static.
* - Be accessible, given the current security context (if applicable).
* - Have exactly the same name as the mocked method.
* - Have exactly the same return type as the mocked method.
* - Have exactly the same number of arguments as the mocked method.
* - Have exactly the same argument types as the mocked method.
*
*
* When determining which method to call, inherited methods are not
* considered - only methods declared on the class of the supplied object are
* taken into account, regardless of their access modifiers.
*
* While in practice the supplied delegate will often be an object of the
* same class as the mock, this is not a requirement - the delegate can be
* of any type, and multiple methods on the same mock may each delegate to
* different objects, each of potentially different classes.
*
* This method may be chained with other then...
methods,
* which will cause the mocked invocation to exhibit the chained
* behaviours, in order, upon multiple calls to the mock.
*
* See {@link MoxyStubber#thenReturn(Object)} for a example of chained stubbing.
*
* @param delegate An object with a compatible method.
*
* @return this
, for ongoing stubbing.
*
* @since 1.0
*/
public MoxyVoidStubber thenDelegateTo(final Object delegate);
/**
* Add a doAction to this method.
*
* doActions are arbitrary actions that are executed, in order,
* during invocation of mocked methods. These actions can be applied to
* any mock, including those that use {@link #thenCallRealMethod()}.
*
* The action receives the actual arguments the method was
* called with as an immutable List
.
*
* It is possible to chain multiple actions on a single invocation,
* for example:
*
*
* Moxy.when(() -> mock.something("arg"))
* .thenDo(args -> System.out.println("mock.something called"))
* .thenDo(args -> customRecorder.record("something", args))
* .thenCallRealMethod();
*
*
* Note: For a given invocation, all matching doActions
* will be invoked, even if they weren't (intentionally) applied to the
* given arguments. This only applies when argument matchers are used.
*
* As an example of this potentially-confusing behaviour, consider the
* following example:
*
*
* Moxy.when(() -> mock.hasTwoArgs(Matchers.any(), Matchers.eqInt(5)))
* .thenDo(() -> System.out.println("Action 1"));
* .thenDo(() -> System.out.println("Action 2"));
*
* Moxy.when(() -> mock.hasTwoArgs(Matchers.eq("Bill"), Matchers.anyInt()))
* .thenDo(() -> System.out.println("Action 3"));
*
* mock.hasTwoArgs("Bill", 5);
*
*
* In this example, the invocation mock.hasTwoArgs("Bill", 5)
matches
* both stubbed invocations, so all actions will run, resulting in the
* following output:
*
*
* Action 1
* Action 2
* Action 3
*
*
* I.e., since the framework has no way to tell exactly which of the two
* potential matching preconditions you actually wanted, it calls them both.
*
* For this reason, you should exercise caution when using matchers with
* doActions, to ensure you only execute actions on the invocations
* you actually want to invoke them on. This is especially true where your
* actions have side effects.
*
* @since 1.0
* @param action The action, usually as a lambda.
*
* @return this
, for continued stubbing.
*/
public MoxyVoidStubber thenDo(Consumer> action);
}