Mockito can't set up when as throws exception in method - java

This seems like it should be simple but I'm running around in circles.
I have:
#Mock
SimpleAbstractCacheWithInputs<Key, Value, Inputs> underlyingCache;
I then try to set up a call on the cache in setup():
when(underlyingCache.getOrCreate(usdgbpKey)).thenReturn(usdgbpCfi);
But this throws a null pointer exception from within getOrCreate() because it's trying to execute the actual code in the real object, not mocked at all, and that isn't set up.
But I don't want to ever run getOrCreate real code, I just want it to return the mocked value!
So how do I do this without having to set up everything inside underlyingCache that I'm never going to use in order to mock this one method call?

If you were concerned about the behavior of a spy or already-stubbed object, I would recommend this syntax, which doesn't rely on calling the mocked object:
doReturn(usdgbpCfi).when(underlyingCache).getOrCreate(usdgbpKey);
...but that all seems right. If you're using the #Mock annotation, then the entire object should be mocked, or null if you've forgotten a Mockito runner/rule/initialization.
There are a few cases where mocking would fail and you get the actual behavior instead:
If the method is final, because then Mockito can't override the method (through a proxy).
If the class is final, because then Mockito can't override the class (through a proxy).
If the class has complicated access semantics, such as a public nested class that accesses private parent methods, because the Java compiler may rewrite the method call through a synthetic method that Mockito can't (easily) mock.

Related

How do I manipulate an argument with mockito

I am using junit to run a few unit tests. One of these calls a method in an object that I mock using mockito like;
#Mock
private MyClass myClass;
I then set up mockito to do something like
Mockito.when(myClass.foo(Mockito.any()).thenReturn(bar);
Now myClass.foo actually takes another one of my classes (say class Person) as an argument and what I would like to do is something like this
Mockito.when(myClass.foo(Person parson)).thenDo(person.setName("Name")).thenReturn(bar);
That is of course pseudo code but I hope it illustrates what I am trying to do. Is this possible?
You need to use thenAnswer or its twin doAnswer method.
See Mockito : doAnswer Vs thenReturn
You should use thenReturn or doReturn when you know the return value at the time you mock a method call. This defined value is returned when you invoke the mocked method.
Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.
If your answers become too complicated, consider using a fake instead of a mock.
In this case if your goal is to set field of Person object you can do that before or after the line:
Mockito.when(myClass.foo(Mockito.any()).thenReturn(bar);
doAnswer() would help do operations based on input, but operations would be performed on copy of arguments not the original arguments.

How does Powermockito whenNew work?

I have tested that incredible feature provided by whenNew some days ago, that allows us to "intercept" constructor calls of any class inside tested environment and return eg. mocked instance of given class. I was wondering what are principles behind this? My first thought was a bytecode manipulation in order to inject proper code blocks to contructor but hey - constructors does not return created instance so this is obviously not an answer.
What would it be then? AOP - intercepting contructor calls and replacing it with return given object statements?
Powermock modifies the bytecode in the calling class (the one with new SomeMockedClass(...)) so that it recovers and uses the mock instance passed into whenNew.
This is not the only way it could be implemented by a mocking library, though. JMockit also mocks constructors, but it does it by modifying the actual constructor instead (which still returns void, of course).

Can JMockit initiate mock objects with argument constructor?

When I put the #Mocked annotation on a object which has only constructor with parameters, will this object be initiated rightly?
When I put the #Mocked annotation on a object which has only constructor with parameters, will this object be initiated rightly?
No.
A mock will be created that has the same interface. That means it will have the same public methods and if the test class is in the same package it will also have the same protected and package private methods accessible.
This mock will not invoke the real methods of the mocked class (unless you configure it so).
This means that for every method that is expected to be called by your code under test (cut) and that has a return value defined you have to configure your mock so that is returns a value your cut shall work with in that particular test.
This configurable return values and the verify capabilities of the mocks are the reason why we use mocking frameworks.
Attention
If you want to mock the call to a method which accesses a member initialized by the mocked classes constructor you have to use the form
doReturn(SOME_VALUE).when(mock).methodToBeCalledByYourCut();
because the form
when(mock.methodToBeCalledByYourCut()).thenReturn(SOME_VALUE);
will raise a NullPointerException in that special case.

Mockito: When is #Mock object get initialized and which constructor it calls

I'm trying to figure out how mockito is working behind in order to debug. I was wondering for the object with #Mock annotation, when is it initialized? Like, before #Before or after #Before?
And if there're several different constructors, how is mockito determines which constructors to call?
And if I use jmockit #Mocked instead, are there any different answers of the questions above?
Thank you!
Mock objects created with Mockito don't call any constructor or static initializer. (This is achieved through Objenesis in older versions of Mockito, and ByteBuddy in newer versions.) Consequently, all of the fields are uninitialized, and no side effects in constructors happen at all including any exceptions you might see thrown.
In contrast, spy objects do have their constructors called. Mockito will default to calling a no-argument constructor (public or private) if you don't initialize the field, and you can call the constructor of your choice inside the initializer.
The order of #Mock annotation initialization depends on which technique you use to initialize mocks:
If you use MockitoJUnitRunner, mocks are initialized after initializer blocks, constructors, and #Rules, and before any other #Befores as defined in BlockJUnit4ClassRunner.
If you use MockitoRule, mocks are initialized before any #Before methods, but in undefined order compared to other #Rules unless you chain them manually with RuleChain.
If you use MockitoAnnotations.initMocks(), mocks are initialized exactly when you call that method, which is after initializer blocks and rules, and (if you call within a #Before method) in undefined order compared to other #Before methods.
#Mocked fields are initialized right after the test class is instantiated by the test runner (JUnit, TestNG), before any #Before/#BeforeMethod-annotated methods get executed.
The mocked instance is created by JMockit without calling any constructor in the mocked class.
The above answers also apply to Mockito (and any other mocking library with similar features).

Ignoring argument

So I'm trying to test a method methodUnderTest which is something like this:
methodUnderTest{
//Other stuff that works nice
this.setterMethod(OtherClass.methodThatErrors(arg1));
}
So I'm trying to avoid that static method call methodThatErrors.
What I'm doing so far:
ClassUnderTest spy = Mockito.spy(objectOfClassUnderTest);
Mockito.doNothing().when(spy).setterMethod(Mockito.any(OtherClass.class));
However this does not work, the method is still being called. I would've thought that it shouldn't call the argument method at all because I've written any for the argument of setterMethod. So how can I prevent this call using Mockito, not PowerMockito.
Edit:
So I managed to mock it by moving the static method call like so:
methodUnderTest{
this.extraSetterMethod(arg1);
}
extraSetterMethod(arg1){
this.setterMethod(OtherClass.methodThatErrors(arg1));
}
I don't really like this solution because it's adding several extra lines of code (even more with javadoc) which just makes the class messier.
The problem here is that the value is coming directly from the static method, and not the setter itself. Whatever value it's getting is coming from the real invocation of the method itself. Mocking out the call to the setter has no effect; it's not the result of the setter that's in error.
This is a scenario in which you have to make a hard decision:
Introduce a parameter to the method so that the call can be easier to mock, or
Use PowerMockito to mock out the call.
I strongly encourage the latter, especially if you're dealing with a legacy code base which is not very forgiving to a signature change.

Categories