Lombok #Synchronized with Mockito throws NPE - java

Given synchronized and Lombok's #Synchronized, the latter causes a NullPointerException when mocking a method under test. Given
public class Problem
{
public Problem()
{
// Expensive initialization,
// so use Mock, not Spy
}
public synchronized String a()
{
return "a";
}
#Synchronized // <-- Causes NPE during tests, literally, here
public String b()
{
return "b";
}
}
and the Jupiter test class
class ProblemTest
{
#Mock
private Problem subject;
#BeforeEach
void setup()
{
initMocks(this);
// There is more mocking. Please don't let the simplicity
// of this example throw you off.
doCallRealMethod().when( subject ).a();
doCallRealMethod().when( subject ).b();
// This is a hack, but works. Can we rely on this?
// ReflectionTestUtils.setField( subject, "$lock", new Object[0] );
}
#Test
void a()
{
// Succeeds
assertEquals( "a", subject.a() );
}
#Test
void b()
{
// NullPointerException during tests
assertEquals( "b", subject.b() );
}
}
Lombok adds something like the following:
private final Object $lock = new Object[0]; // We can't rely on this name
...
public String b()
{
synchronized($lock)
{
return "b";
}
}
How to mock a method that is decorated with Lombok's default #Synchronized annotation?
Here is the stack trace, though it is unhelpful. I suspect Lombok adds a field as in my example above, and of course that is not injected into the mock, so voilĂ , NPE.
java.lang.NullPointerException
at com.ericdraken.Problem.b(Problem.java:16) // <-- #Synchronized keyword
at com.ericdraken.ProblemTest.b(ProblemTest.java:43) // <-- assertEquals( "b", subject.b() );
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
... [snip] ...
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

This isn't an issue with Lombok, the following also fails.
#ExtendWith({MockitoExtension.class})
#MockitoSettings(strictness = Strictness.LENIENT)
public class ProblemTest {
#Mock
private Problem subject;
#BeforeEach
void setup()
{
doCallRealMethod().when( subject ).c();
}
#Test
void c()
{
// NullPointerException during tests
assertEquals( "c", subject.c() );
}
}
class Problem
{
private final Map<String,String> c = new HashMap<>(){{put("c","c");}};
public String c(){
return c.get("c");
}
}
To be precise, you are not really mocking Problem, you are partially mocking via doCallRealMethod hence the issue.
This is also called out in Mockito's documentation,
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
doCallRealMethod() is called on a mock which is not guaranteed to have the object created the way it's supposed to be.
So to answer your question, yes that's the way you create a mock, but doCallRealMethod is always a gamble irrespective of Lombok.
You can use spy if you really want to call the actual method.
#Test
void c() {
Problem spyProblem = Mockito.spy(new Problem());
assertEquals("c", spyProblem.c());
verify(spyProblem, Mockito.times(1)).c();
}

The core problem is that you are combining calling the real method with a mock rather than a spy. This is dangerous in general, as whether it works for anything depends very much on the internal implementation of the method in question.
Lombok only matters because it works by altering that internal implementation during compilation, in a way that happens to require proper object initialization to work where the original method does not.
If you're going to configure a mock to call the real method, you should probably use a spy instead.

Synopsis
Project Lombok has the #Synchronized annotation on methods to hide the underlying and auto-generated private lock(s), whereas synchronized locks on this.
When using a Mockito mock (not a spy, because there are situations when we don't want a full object instantiated), fields are not initialized. That means as well the auto-generated "lock" field is null which causes the NPE.
Solution 1 - Field injection
Looking at Lombok source code, we see that Lombok uses the following lock names:
private static final String INSTANCE_LOCK_NAME = "$lock";
private static final String STATIC_LOCK_NAME = "$LOCK";
Unless Lombok suddenly changes this in the future, this means we can do field injection even if it feels like a "hack":
#BeforeEach
void setup()
{
initMocks(this);
...
ReflectionTestUtils.setField( subject, "$lock", new Object[0] );
}
Solution 2 - Declare a lock, then field injection
The question asks about #Synchronized, not #Synchronized("someLockName"), but if you can explicitly declare the lock name, then you can use solution one with confidence about the lock field name.

Related

Sometimes we get error: "Previous MockitoSession was not concluded with 'finishMocking()'" [duplicate]

I am getting following exception while running the tests. I am using Mockito for mocking. The hints mentioned by Mockito library are not helping.
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276)
..........
Test Code from DomainTestFactory. When I run the following test, I see the exception.
#Test
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
Mockito.when(mainModel.getList()).thenReturn(getSomeList()); // Line 355
}
private List<SomeModel> getSomeList() {
SomeModel model = Mockito.mock(SomeModel.class);
Mockito.when(model.getName()).thenReturn("SomeName"); // Line 276
Mockito.when(model.getAddress()).thenReturn("Address");
return Arrays.asList(model);
}
public class SomeModel extends SomeInputModel{
protected String address;
protected List<SomeClass> properties;
public SomeModel() {
this.Properties = new java.util.ArrayList<SomeClass>();
}
public String getAddress() {
return this.address;
}
}
public class SomeInputModel{
public NetworkInputModel() {
this.Properties = new java.util.ArrayList<SomeClass>();
}
protected String Name;
protected List<SomeClass> properties;
public String getName() {
return this.Name;
}
public void setName(String value) {
this.Name = value;
}
}
You're nesting mocking inside of mocking. You're calling getSomeList(), which does some mocking, before you've finished the mocking for MyMainModel. Mockito doesn't like it when you do this.
Replace
#Test
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}
with
#Test
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
List<SomeModel> someModelList = getSomeList();
Mockito.when(mainModel.getList()).thenReturn(someModelList);
}
To understand why this causes a problem, you need to know a little about how Mockito works, and also be aware in what order expressions and statements are evaluated in Java.
Mockito can't read your source code, so in order to figure out what you are asking it to do, it relies a lot on static state. When you call a method on a mock object, Mockito records the details of the call in an internal list of invocations. The when method reads the last of these invocations off the list and records this invocation in the OngoingStubbing object it returns.
The line
Mockito.when(mainModel.getList()).thenReturn(someModelList);
causes the following interactions with Mockito:
Mock method mainModel.getList() is called,
Static method when is called,
Method thenReturn is called on the OngoingStubbing object returned by the when method.
The thenReturn method can then instruct the mock it received via the OngoingStubbing method to handle any suitable call to the getList method to return someModelList.
In fact, as Mockito can't see your code, you can also write your mocking as follows:
mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);
This style is somewhat less clear to read, especially since in this case the null has to be casted, but it generates the same sequence of interactions with Mockito and will achieve the same result as the line above.
However, the line
Mockito.when(mainModel.getList()).thenReturn(getSomeList());
causes the following interactions with Mockito:
Mock method mainModel.getList() is called,
Static method when is called,
A new mock of SomeModel is created (inside getSomeList()),
Mock method model.getName() is called,
At this point Mockito gets confused. It thought you were mocking mainModel.getList(), but now you're telling it you want to mock the model.getName() method. To Mockito, it looks like you're doing the following:
when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);
This looks silly to Mockito as it can't be sure what you're doing with mainModel.getList().
Note that we did not get to the thenReturn method call, as the JVM needs to evaluate the parameters to this method before it can call the method. In this case, this means calling the getSomeList() method.
Generally it is a bad design decision to rely on static state, as Mockito does, because it can lead to cases where the Principle of Least Astonishment is violated. However, Mockito's design does make for clear and expressive mocking, even if it leads to astonishment sometimes.
Finally, recent versions of Mockito add an extra line to the error message above. This extra line indicates you may be in the same situation as this question:
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
For those who use com.nhaarman.mockitokotlin2.mock {}
Workaround 1
This error occurs when, for example, we create a mock inside another mock
mock {
on { x() } doReturn mock {
on { y() } doReturn z()
}
}
The solution to this is to create the child mock in a variable and use the variable in the scope of the parent mock to prevent the mock creation from being explicitly nested.
val liveDataMock = mock {
on { y() } doReturn z()
}
mock {
on { x() } doReturn liveDataMock
}
Workaround 2
Make sure all your mocks that should have a thenReturn.
GL
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
E.g. thenReturn() may be missing.
For mocking of void methods try out below:
//Kotlin Syntax
Mockito.`when`(voidMethodCall())
.then {
Unit //Do Nothing
}
AbcService abcService = mock(AbcService.class);
Check the syntax:
doThrow(new RunTimeException()).when(abcService).add(any(), any())
Common Mistake as seen below:
A. doThrow(new RunTimeException()).when(abcService.add(any(), any()))
Similarly, check for when().thenReturn(), so on.
I am so exited with detailed answer of #Luke Woodward that want to share a workaround.
As #Luke Woodward explained, we can not have two calls like
when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);
Than can occurs in call chain.
But in case you will use construction:
doReturn(mockToken("token3")).when(mock).getAccessToken();
when
OAuth2AccessToken mockToken(String tokenVal){
OAuth2AccessToken token = Mockito.mock(OAuth2AccessToken.class);
doReturn( 60 ).when(token).getExpiresIn();
doReturn(tokenVal).when(token).getValue();
return token;
}
all will works as expected.

Unable to execute test method from mocked class

I am writing unit test for methods to find banks near my location.
I mocked the class and tried to call the methods.
But, control is not going to method to execute it.
Below is unit test case.
#Test
public void testFindBanksByGeo() {
String spatialLocation = "45.36134,14.84400";
String Address = "Test Address";
String spatialLocation2 = "18.04706,38.78501";
// 'SearchClass' is class where 'target' method resides
SearchClass searchClass = Mockito.mock(SearchClass.class);
BankEntity bank = Mockito.mock(BankEntity.class);
// 'findAddressFromGeoLocation' and 'getGeo_location' to be mocked. They are called within 'target' method
when(searchClass.findAddressFromGeoLocation(anyString())).thenReturn(Address);
when(bank.getGeo_location()).thenReturn(spatialLocation2);
// 'writeResultInJson' is void method. so needed to 'spy' 'SearchClass'
SearchClass spy = Mockito.spy(SearchClass.class);
Mockito.doNothing().when(spy).writeResultInJson(anyObject(), anyString());
//This is test target method called. **Issue is control is not going into this method**
SearchedBanksEntity searchBanksEntity = searchClass.findNearbyBanksByGeoLocation(spatialLocation, 500);
assertNull(searchBankEntity);
}
What i have tried is also calling the real method on it,
Mockito.when(searchClass.findNearbyBanksByGeoLocation(anyString(), anyDouble())).thenCallRealMethod();
This calls real method but the methods i mocked above, are executing like real one. Means 'mocked methods' are not returning what i asked them to return.
So, what wrong i am doing here ?
why method is not executing?
The method is not getting called because you are calling it on a mock. You should call the method on an actual object.
Or you could use something like this before invoking the method.
Mockito.when(searchClass.findNearbyBanksByGeoLocation(Mockito.eq(spatialLocation), Mockito.eq(500))).thenCallRealMethod();
But I think this is not the way you should write the test. You shouldn't be mocking SearchClass in the first place. Instead there would be a dependency in SearchClass which gets you the address and geo location. You should be mocking that particular dependency.
OK, let's say we have this code:
class Foo {
// has a setter
SomeThing someThing;
int bar(int a) {
return someThing.compute(a + 3);
}
}
We want to test Foo#bar(), but there's a dependency to SomeThing, we can then use a mock:
#RunWith(MockitoJunitRunner.class)
class FooTest {
#Mock // Same as "someThing = Mockito.mock(SomeThing.class)"
private SomeThing someThing,
private final Foo foo;
#Before
public void setup() throws Exception {
foo = new Foo(); // our instance of Foo we will be testing
foo.setSomeThing(someThing); // we "inject" our mocked SomeThing
}
#Test
public void testFoo() throws Exception {
when(someThing.compute(anyInt()).thenReturn(2); // we define some behavior
assertEquals(2, foo.bar(5)); // test assertion
verify(someThing).compute(7); // verify behavior.
}
}
Using a mock we are able to avoid using a real SomeThing.
Some reading:
http://www.vogella.com/tutorials/Mockito/article.html
https://github.com/mockito/mockito/wiki

Mockito NotaMockException

I am facing an issue with Mockito junit testing. I am new to it and am a bit confused with the problem I am facing. Any help on this would be appreciated.
class Activity{
public void firstMethod(){
String str = secondMethod();
}
public String secondMethod(){
String str = null;
/* some Code */
return str;
}
}
Getting exception :
*org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!*
in the below code
class ActivityTest(){
Activity act;
#Before
public void setup(){
act = new Activity();
}
#Test
public void testFirstMethod(){
Mockito.doReturn(Mockito.anyString()).when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
I am aware that activity is not a mock but I am not sure for a way around this as secondMethod() is a method in the same class. I need to write rule for secondMethod() as I have already done its Unit Testing. The definition of secondMethod() consists has external dependencies. Should I be mocking the external dependencies present in secondMethod() and writing rules for them rather than rule for secondMethod()?
I found this post:
Mockito Spy'ing on the object being unit tested
However separating the secondMethod() into a different class does not make sense. My method is related to this class. Creating a different class for testing does not seem right to me. Even mocking the actual class using spy() is not the most correct way as already explained in the post.
I don't think I should be creating a mock of the Activity class as that is the class I am testing. I would really appreciate help and insights into this.
As you noted, act is not a mock, and therefore you cannot record behavior on it. You could use Mockito.spy to, well, spy (or partially mock) the act object so that you only record the behavior of secondMethod and execute the actual code for firstMethod.
Note, however, that matchers can't be used in doReturn calls regardles of how you're mocking or spying your object. A return value must be a concrete object.
class ActivityTest() {
Activity act;
#Before
public void setup(){
act = Mockito.spy(new Activity()); // Here!
}
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
A slightly more elegant syntax allows you to use annotations instead of explicitly calling Mockito.spy, but it's a matter of taste really:
#RunWith(MockitoJUnitRunner.class)
class ActivityTest() {
#Spy
Activity act = new Activity();
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
There is no reason to mock anything in this example. Since there are no dependencies and both methods are public, you can test them directly.
public class ActivityTest() {
private Activity act = new Activity();
#Test
public void testSecondMethod(){
assertEquals("expected-value", act.secondMethod());
}
#Test
public void testFirstMethod() {
act.firstMethod();
// success if no exception occurs
}
}
Since firstMethod does not have any detectable effect on the Act instance, nor on any dependency (since there are none) you can simply call the method and be satisfied if no exception is thrown. One could also reason that such a method should not be tested at all.
I assume the example given is a simplification of a class where calling firstMethod actually does have side effects, who knows...
Here are some hints:
Mock the Activity.
Tweak the behavior of secondMethod with when / then / doReturn
Use doCallRealMethod when firstMethod is invoked.
Hope it helps.

Mock method as parameter another method

I have got a problem with testing how many times concrete methods (IFunction in the Operation instance) is invoked.
According to:
http://easymock.org/user-guide.html#mocking-annotations
http://www.ibm.com/developerworks/library/j-easymock/
How to use EasyMock expect
I wrote something as:
class Operation{
public double[] calculateSth(IFunction function, int [] t){
for(int i=0 ; i<5 ; i+=1)
function(t, new int[]{1,2,3});
return new double[]{1,2,3};
}
}
interface IFunction{
double f(int[] a, int[]b);
}
class ConcreteF implements IFunction{
double f(int[]a, int[]b){
return 5;
}
}
And my test class:
#TestSubject
Operation op;
#Mock
IFunction function;
#Before
public void setUp() throws Sth{
op=new Operation();
function = EasyMock.createMock(IFunction.class);
}
#Test
public void howManyTimes(){
EasyMock.expect(function.f(EasyMock.notNull(), EasyMock.notNull())
)
.andReturn((double)EasyMock.anyDouble()).times(3);
EasyMock.replay(function);
op.calculateSth(function, new double[]{0,0,0});
//verify
EasyMock.verify(function);
}
Result:
java.lang.NullPointerException
at org.easymock.internal.Injector.injectMocks(Injector.java:80)
at org.easymock.EasyMockSupport.injectMocks(EasyMockSupport.java:624)
at org.easymock.EasyMockRunner.withBefores(EasyMockRunner.java:50)
It's my first time using easymock and i don't know how to fix it ;/
I'll answer this question without going into the details of whether the original method does anything useful (the code doesn't even compile anyway), let alone the test method.
#TestSubject Operation op;
This line is a suspect. I realize that you are instantiating it in the #Before annotated setUp method, but it looks like the Easymock tries to inject the mocks (the ones annotated with #Mock) before it does anything (and understandably so) and blows up since the reference is null at that point.
The annotation support introduced in v3.2 is also seen as a way to eliminate the need for setUp method. But you seem to be mixing both and using it wrongly. Choose one or the other - I'd recommend you to use the annotations.
Quoting the Easymock user guide (this user guide is as good as it can ever be, so be sure read this up before using the library),
#RunWith(EasyMockRunner.class)
public class ExampleTest {
#TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
#Mock
private Collaborator mock; // 1
#Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}
The mock is instantiated by the runner at step 1. It is then set by
the runner, to the listener field on step 2. The setUp method can be
removed since all the initialization was done by the runner.

Unit Testing Java Code - Mocking a non-static method of a different class

public class First {
public First(){
}
public String doSecond(){
Second second = new Second();
return second.doJob();
}
}
class Second {
public String doJob(){
return "Do Something";
}
}
Here I want to test the method "doSecond()" of class "First". For the same, I want to mock the method "doJob" of class "Second".
I know that I can create a mocked instance of class "Second" using the code below.
Second sec = mock(Second.class);
when(sec.doJob()).thenReturn("Stubbed Second");
But I cannot relate this mocked instance with class "First" as of the current code.
Without refactoring the source code, is there any way by which i can achieve the requirement.
Please help.
Take a look at powermock's ability to intercept calls to new and return mocks instead
https://code.google.com/p/powermock/wiki/MockConstructor
This doesn't require changing any sourcecode.
here's the test code where we actually return a mock when First.doSecond() calls new Second()
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class TestFirst {
#Test
public void mockSecond() throws Exception{
Second mock = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mock);
PowerMockito.when(mock.doSecond()).thenReturn("from mock");
First first = new First();
assertEquals("from mock", first.doSecond());
}
}
It's tricky to mock an instance that you create inside of a method, but it's possible.
Using PowerMock, you can accomplish this with the PowerMock.expectNew() method:
#RunWith(PowerMockRunner.class)
#PrepareForTest(First.class)
public class StackOverflowTest {
#Test
public void testFirst() throws Exception {
Second secondMock = EasyMock.createMock(Second.class);
PowerMock.expectNew(Second.class).andReturn(secondMock);
expect(secondMock.doSecond()).andReturn("Mocked!!!");
PowerMock.replay(secondMock, Second.class);
String actual = new First().doSecond();
PowerMock.verify(secondMock, Second.class);
assertThat(actual, equalTo("Mocked!!!"));
}
}
Effectively, PowerMock is proxying the creation of the new object and substituting whatever value we want when we invoke doSecond().
So, it's possible. However, this is a terrible practice to get into.
One typically wants to mock objects if they involve an outside concern, such as another layer (i.e. database, validation), or if the desired output is coming from other objects that are injected but are safe enough to consider tested.
If your method is capable of getting or retrieving data from a non-injectable source, you should not want to mock that out.
Considering that your method is simple and straightforward, you should really not need to do any mocks here at all. But if you felt that you were forced to, you could do one of a few things:
Create a factory for the creation of Second, and mock the results of the returning factory object with Mockito.
Pass in an instance of Second to that method, and use Mockito as the mock instance.
Declare it as a field (i.e. injected dependency), and use Mockito.
For completeness, here is how the test can be written with the JMockit mocking API, without any refactoring of the original code under test:
public class ExampleTest
{
#Test
public void firstShouldCallSecond(#Mocked final Second secondMock) {
new NonStrictExpectations() {{
secondMock.doJob(); result = "Mocked!!!";
}};
String actual = new First().doSecond();
assertEquals("Mocked!!!", actual);
}
}

Categories

Resources