Mockito: How to easily stub a method without mocking all parameters - java

I have a method i'd like to stub but it has a lot of parameters.
How can i avoid mocking all parameters but still stub the method.
Ex:
//Method to stub
public void myMethod(Bar bar, Foo foo, FooBar fooBar, BarFoo barFoo, .....endless list of parameters..);

I don't quite follow what problem you're having using Mockito. Assuming you create a mock of the interface that contains your myMethod() method, you can then verify only the parameters to the method that you are interested in. For example (assuming the interface is called MyInterface and using JUnit 4):
#Test
public void test() {
MyInterface myInterface = mock(MyInterface.class);
FooBar expectedFooBar = new FooBar();
// other testing stuff
verify(myInterface).myMethod(any(), any(), eq(expectedFooBar), any(), ...);
}
You'll need to do a static import on the Mockito methods for this to work. The any() matcher doesn't care what value has been passed when verifying.
You can't avoid passing something for every argument in your method (even if it's only NULL).

use mockito.any
if myobj mymethod accepts string, string, bar for instance
to stub a call
Mockito.when(myojb.myMethod(Mockito.anyString(),Mockito.anyString(),Mockito.any(Bar.class)))
.thenReturn(amockedobject);
to verify SteveD gave the answer already
Mockito.verify(myojb).myMethod(
Mockito.anyString(),Mockito.anyString(),Mockito.any(Bar.class)));

Create a wrapper class which calls the real method and fills in all the arguments but the ones you supply (a.k.a "delegation").
And at the next opportunity, file a bug against the project asking to move the parameters to a config object.

Related

Not able to run ByteBuddy interceptor when #Morph argument is specified

I need to create a custom classes based on some input. What I have atm is this:
final Class service = ...;
final Method method = ...;
final DynamicType.Unloaded unloadedType = new ByteBuddy()
.subclass(Object.class)
.name(service.getClass().getSimpleName() + "DynamicResolver")
.defineMethod(
endpointName,
resolveReturnType(method),
Modifier.PUBLIC)
.withParameters(parameters)
.intercept(MethodDelegation
.withDefaultConfiguration()
.withBinders(Morph.Binder.install(Morphing.class))
.to(interceptor).andThen(
MethodCall.invoke(method).on(service).withArgument(arguments)
))
.make()
What I am doing here is creating a class with a single method that delegates to provided one. However, the created method and delegate method have a bit different parameters. The created method has one argument more (in parameters). The created method does not take that argument, hence the arguments array with argument indexes (one argument less).
So far it's OK. Now, I need to add additional argument when calling delegation method. For the sake of simplicity of the example, imagine we have to add one more string to delegate call.
As I saw from the documentation, the way to manipulate the arguments is using #Morph. So I did:
public interface Morphing<T> {
T invoke(Object[] args);
}
and my interceptor:
public class Interceptor {
#RuntimeType
public Object invoke(
#Morph final Morphing<Integer> m,
#AllArguments final Object[] args
) {
System.out.println("!!!");
return m.invoke(args);
}
}
Unfortunately, this is not working. When I remove the #Morph argument, the interceptor gets called.
What am I missing here?
EDIT: Is the #Morph used only for subclasses and not when delegating to another instance?
EDIT2: example
Byte Buddy is binding a method of the Object class such that your desired interceptor is no longer triggered. You can add filter(isDeclaredBy(MyInterceptor.class)) after the withDefaultConfiguration() to avoid this. Doing so, you will get an exception that Byte Buddy cannot bind any of your methods.
The reason that #Morph makes the class ineligable is that there is no super method to be called. In your example, you are defining a new method which does not have an original implementation. You'd need to override an existing method to use the annotation.

How do i verify the call to mocked instance when the instance takes "this" as parameter

I have a method which has call to event publisher, i want to verify the call to this publisher.
public void submitRegistrationForm(String registrationKey, RegistrationFormSubmitDTO registrationFormSubmitDTO) {
applicationEventPublisher.publishEvent(new RegistrationCompletedEvent(this, targetCustomerRegistration));
}
So, i mocked the applicationEventPublisher class and i had verified the call to it like this:
verify(applicationEventPublisher, times(1)).publishEvent(any(RegistrationCompletedEvent.class));
but i was told not to use any(), instead i need to build the concrete instance.
how can i verify the method which takes "this" as parameter.
You can use an argument captor to capture the RegistrationCompletedEvent and assert on it...
ArgumentCaptor<RegistrationCompletedEvent > argument = ArgumentCaptor.forClass(RegistrationCompletedEvent .class);
verify(applicationEventPublisher).publishEvent(argument.capture());
assertEquals("whatever", argument.getValue().something());

Mocking the arguments passed to callbacks (lambdas)

How would I mock methods that accept a lambda using Mockito so that I am able to control which arguments are passed into the callback? I am specifically trying to mock the JDBI method useExtension which is used like this:
jdbi.useExtension(OrgUnitDao.class, dao -> {
// Skip if already loaded
// Skip if already loaded
if (dao.orgUnitsAreLoaded()) {
I would like to substitute the dao object passed back into the callback so that I could control the branching using the return value of dao.orgUnitsAreLoaded().
The signature looks like this
public <E,X extends Exception> void useExtension(Class<E> extensionType,
ExtensionConsumer<E,X> callback)
throws NoSuchExtensionException,
X extends Exception
This is the full answer to my question. It's simplified down to the very basics of how to do the stubbing and so doesn't reflect the production code I am to test, but it shows exactly the mechanics needed to do it.
final Jdbi jdbi = mock(Jdbi.class);
doAnswer(invocation -> {
System.out.println("this is the doAnswer lambda - just setting up the answer and the mocks");
final Class<OrgUnitDao> daoClass = invocation.getArgument(0);
final ExtensionConsumer callback = invocation.getArgument(1);
final OrgUnitDao mock1 = mock(daoClass);
when(mock1.orgUnitsAreLoaded()).thenReturn(false);
// call the actual callback method
callback.useExtension(mock1);
return null;
}).when(jdbi).useExtension(eq(OrgUnitDao.class), any());
// This is the method call I am to test
// Regard this as hidden away in some outer method in
// the System-Under-Test, but that I have been able
// to inject all its dependencies
jdbi.useExtension(OrgUnitDao.class, new Foo());
/// Further down, outside of the method
// Only replaced the lambda with this to get toString() for debugging ...
class Foo implements ExtensionConsumer<OrgUnitDao, RuntimeException> {
#Override
public void useExtension(OrgUnitDao orgUnitDao) throws RuntimeException {
System.out.println("A real method call, now using the passed in mocked dao:" + orgUnitDao.orgUnitsAreLoaded());
}
#Override
public String toString() {
return "OrgUnitDao class";
}
}
To parallel the conversation on the question "Calling callbacks with Mockito", your lambda might be called synchronously during the execution of your method-under-test, or it might be called later based on some external factor or interaction. Like Dawood's answer there, your answer here using a Mockito Answer will work, and is the only way to go if you are looking for the synchronous style (where mockJdbi calls your lambda immediately before methodUnderTest returns). If your lambdas are going to be called asynchronously, or if your system tolerates you calling the lambda asynchronously, you might want to test the state after your method-under-test returns but before you interact with the lambda.
// MockitoJUnitRunner, MockitoRule, or MockitoAnnotations.initMocks populate these.
// Especially useful for the ArgumentCaptor's generic arguments.
#Mock Jdbi mockJdbi;
#Mock OrgUnitDao mockOrgUnitDao;
#Captor ArgumentCaptor<ExtensionConsumer<OrgUnitDao, RuntimeException>>
extensionConsumerCaptor;
#Test public void yourTest() throws Exception {
// No stubbing needed! Just create the system under test.
YourSystemUnderTest systemUnderTest = new YourSystemUnderTest(mockJdbi);
// Call the method under test, which presumably calls useExtension(...).
systemUnderTest.methodUnderTest();
// Assert anything that should be true before the lambda is called.
assertFalse(systemUnderTest.getSomeState());
// Confirm that useExtension was called, and simultaneously acquire the lambda.
// ArgumentCaptor.capture() is a matcher, so every argument requires a matcher like eq.
verify(mockJdbi).useExtension(eq(OrgUnitDao.class), extensionConsumerCaptor.capture());
// Prepare the mock DAO and call the lambda.
when(mockDao.getFoo()).thenReturn("bar");
extensionConsumerCaptor.getValue().useExtension(mockDao);
// Assert anything that should be true after the lambda is called.
assertTrue(systemUnderTest.getSomeState());
}
Though lambdas reduce the boilerplate previously associated with anonymous inner classes, you may also prefer using the Captor style because it saves you from creating lengthy Answer implementations and hiding your test assertions or Mockito verifications in them. This is especially tempting if your project prefers BDD-style mocks with clear "given-when-then" structure (though my example more-closely resembles "given-when-then-when-then").

mockito - how to check an instance inside a method

I am new to Mockito, I am trying to verify the attributes of an object which gets created inside a method.
pseudo code below:
class A{
...
public String methodToTest(){
Parameter params = new Parameter(); //param is basically like a hashmap
params.add("action", "submit");
return process(params);
}
...
public String process(Parameter params){
//do some work based on params
return "done";
}
}
I want to test 2 things:
when I called methodToTest, process() method is called
process() method is called with the correct params containing action "submit"
I was able to verify that process() is eventually called easily using Mockito.verify().
However trying to check that params contains action "submit" is very difficult so far.
I have tried the following but it doesn't work :(
BaseMatcher<Parameter> paramIsCorrect = new BaseMatcher<Parameter>(){
#Overrides
public boolean matches(Object param){
return ("submit".equals((Parameter)param.get("action")));
}
//#Overrides description but do nothing
}
A mockA = mock(A);
A realA = new A();
realA.methodToTest();
verify(mockA).process(argThat(paramIsCorrect))
Any suggestion ?
If you have got verify() to work, presumably it is just a case of using an argument matcher to check the contains of params.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#3
The example given in the above docs is verify(mockedList).get(anyInt()). You can also say verify(mockedList).get(argThat(myCustomMatcher)).
As an aside, it sounds like you are mocking the class under test. I've found that this usually means I haven't thought clearly about either my class or my test or both. In your example, you should be able to test that methodToTest() returns the right result irrespective of whether or not it calls process() because it returns a String. The mockito folk have lots of good documentation about this sort thing, particularly the "monkey island" blog: http://monkeyisland.pl/.
Just pass Parameter in as a constructor argument to a constructor of the class A, then use a mocked instance/implementation of Parameter in your test and verify on the mock. That is how it is normally done - you separate your classes and compose them using constructor injection, that enables you to pass in mocks for testing purposes (it also allows rewiring the application and exchanging some commons a lot easier).
If you need to create Parameter on every function invocation you should use a factory that creates Parameter instances and pass that in. Then you can verify on the factory as well as the object created by the factory.

easymock method matcher for class argument

I have a method with signature as follows:
public <T extends S> T foo(final Class<T> clazz){
.....
.....
}
How do I mock this method in easymock?
I tried following two lines in my test class but still the expected object is not returned, so I get NullPointerException.
Capture<Class<MyClass>> classCapture = new Capture<Class<MyClass>>();
expect(someObject.foo(EasyMock.capture(classCapture))).andReturn(testObject);
And testObject is initialized in the test class, which I want to get returned when
foo()
is called. Where am I doing wrong?
I'm not sure why you want to capture the variable in this instance, but your problem is the way you typed your command means you are looking for a method foo() without any arguments.
You need to you need to use and() to chain the capture and the argument matcher requirements for the method call:
expect(someObject.foo(EasyMock.and(
EasyMock.capture(classCapture),
anyObject()))
)
.andReturn(testObject);
Then after you call your mock in replay mode you can get the captured argument back with capture.getValue()
replay(someObject);
assertSame(testObject, someObject.foo(MyClass.class));
assertEquals(MyClass.class, classCapture.getValue());

Categories