I have a class that contains the following method, which I do not expect to ever return null:
public String getAutoSaveDir() {
if (autoSaveDir == null || autoSaveDir.isEmpty()) {
return System.getProperty("java.io.tmpdir");
} else {
return autoSaveDir;
}
}
I need to mock this class with #Injectable for other reasons.* Unfortunately, this means that this method returns null:
#Tested
private MyClass myClass;
#Injectable
private ClassContainingMethod classContainingMethod;
#Test
public void myTest() {
// Calls classContainingMethod.getAutoSaveDir()
myClass.saveFile();
}
This unfortunately fails, as getAutoSaveDir() returns null. I confirmed that System.getProperty("java.io.tmpdir") does not return null, so it seems that JMockit is mocking the method to return null, when I don't want it to.
I am aware that I can set up an Expectations block to tell it to just return System.getProperty("java.io.tmpdir"), but it seems really silly to mock it to return something that it would be returning anyway if unmocked.
How can I have JMockit not mock this method?
I am using JMockit 1.22 (would love to use a later version, but we have several instances of mocking private methods, which isn't allowed in later versions).
* I have to use #Injectable because the field is annotated with #Autowired. If I try to use a real instance, I get this error: java.lang.IllegalStateException: Missing #Injectable for field MyClass#classContainingMethod, of type com.example.ClassContainingMethod
Related
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.
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.
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
I faced next issue when I have been writing Junit tests with using Mockito. My test invokes methods on real object instead mock object and I receive NullPointerException. Here is my code:
public class JSFUtilsTest {
public JSFUtilsTest() { }
JSFUtils jsfUtils = mock(JSFUtils.class);
FacesContext facesContext = ContextMocker.mockFacesContext();
ExternalContext extContext = mock(ExternalContext.class);
Application app = mock(Application.class);
ExpressionFactory exFactory = mock(ExpressionFactory.class);
ELContext elContext = mock(ELContext.class);
ValueExpression valExp = mock(ValueExpression.class);
#Test
public void testResolveExpression() {
when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){
public Object answer(InvocationOnMock invocation){
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
return valExp.getValue(elContext);
}
});
jsfUtils.resolveExpression(anyString());
verify(jsfUtils).resolveExpression(anyString());
assertNotNull(jsfUtils.resolveExpression(anyString()));
}
}
Instead calling resolveExpression() on Mock, I have got calling on JSFUtils object. JSFUtils.java and JSFUtilsTest.java are located in different packages. Can anybody help me? Thanks in advance!
I assume that this is just an example and in real test you do not call methods on the mock directly, but inject the dependencies to OUT.
You are expecting your mock to answer when you are calling jsfUtils.resolveExpression("expression"). In fact you are not calling it. I would suggest to change it to jsfUtils.resolveExpression(anyString()) and if you need it to be called with some specific string, you can check it the verify block: verify(jsfUtils).resolveExpression("expression");
Also calling jsfUtils.resolveExpression(anyString()); is not the right approach. Method anyString() is designed for stubbing not for real call.
Instead calling resolveExpression() on Mock, I have got calling on JSFUtils object.
Then do not create a mock, but a spy:
//JSFUtils jsfUtils = mock(JSFUtils.class);
JSFUtils jsfUtils = spy(new JSFUtils(/* mocks of dependencies if needed */));
But this is only needed if want to mock the return value of some other method in your class under test to force isolation of your unit.
This is not the case in your example as far as I see. So just write:
//JSFUtils jsfUtils = mock(JSFUtils.class);
JSFUtils jsfUtils = new JSFUtils(/* mocks of dependencies if needed */);
#Test
public void testResolveExpression() {
when(jsfUtils.resolveExpression("expression")).thenAnswer(new Answer<Object>(){
public Object answer(InvocationOnMock invocation){
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
return valExp.getValue(elContext);
}
});
jsfUtils.resolveExpression(anyString());
verify(jsfUtils).resolveExpression(anyString());
assertNotNull(jsfUtils.resolveExpression(anyString()));
This does not make any sense:
You mock the method of your class under test (cut) and then call that very same method. This way you do not verify the behavior of your cut but the behavior of the mocking framework.
Also you call the method twice within the same test method. You should avoid that.
You should change your test to this:
#Test
public void testResolveExpression() {
// arrange (test case specific setup of mocks and DTOs)
when(facesContext.getApplication()).thenReturn(app);
when(app.getExpressionFactory()).thenReturn(exFactory);
when(facesContext.getELContext()).thenReturn(elContext);
when(exFactory.createValueExpression(elContext, "expression", Object.class)).thenReturn(valExp);
when(valExp.getValue(elContext)).thenReturn(anyObject());
// act (call real method on real object)
Object result = jsfUtils.resolveExpression("a valid input");
// assert
assertNotNull(result );
}
I'm new to Mockito and working on a basic example below. If I comment out the stubbed line below the test still passes, what am I doing wrong?
I would have expected the test to fail if I remove the stubbed line as the 'serviceUnderTest' would then not return the correct result from the underlying call to the 'doSomething' method in the mocked dependency?
public class MyTest {
private MyService serviceUnderTest;
#Mock
private MyHelper mockedDependency;
#Before
public void doBeforeEachTestCase()
{
MockitoAnnotations.initMocks(this);
serviceUnderTest = new MyServiceImpl();
serviceUnderTest.setMyHelper(mockedDependency);
}
#Test
public void test1()
{
try
{
SomeObject someObject = null;
// create my stub
stub(mockedDependency.doSomething("123", false, false)).thenReturn(someObject);
// run the implementation
ServiceResult serviceResult = serviceUnderTest.anotherMethod("123", false, false);
// check the state
assertNotNull(serviceResult);
// check the behaviour of the mock
verify(mockedDependency).doSomething("123", false, false);
}
catch(Exception e)
{
fail();
}
}
}
At the time you do your stubbing, someObject is null. So you're setting up the mock to return null from that method.
But null is the default value that a mock will return anyway, from a method that returns an object. Your stubbing actually makes no difference. Note that there are some exceptions to this rule.
If a method returns a collection, then the default return will be an empty collection.
If a method returns one of the wrapper types, then the default return will be zero or false, rather than null.
The toString method returns the name of the mock.
Turns out it was my own misunderstanding of Mockito!
The test was always passing because of the irrelevance of the stubbed method in this case. The stubbed method is used to provide a response to a method call in the service under test, it does not mean that the actual method that I'm verifying at the end of the test is not called.
The method I'm verifying is called in the service under test and the stub makes no difference to this, hence it passes.
At first, if it's a pure unit test you can get rid of #Before section using #RunWith and #InjectMocks annotations. They will handle the initialization phase.
Second, you don't nee to put try-catch blocks, you can just declare the Exception in your testMethod.
And it's better to use when() instead of stub(), like this:
#RunWith(MockitoJUnitRunner.class) public class MyTest {
#Mock
private MyHelper mockedDependency;
#InjectMocks
private MyService serviceUnderTest;
#Test
public void test1() throws Exception {
SomeObject someObject = null;
// create my stub
when(mockedDependency.doSomething("123", false, false)).thenReturn(someObject);
// run the implementation
ServiceResult serviceResult = serviceUnderTest.anotherMethod("123", false, false);
// check the state
assertNotNull(serviceResult);
// check the behaviour of the mock
verify(mockedDependency).doSomething("123", false, false);
}}
In your case line when(mockedDependency.doSomething is not important - test is checking the desired behaviour of MyServiceImpl anyway.