I have a class which contains an public static method getProduct(String name):
public class ProductManager {
public static Product getProduct(String name) {
Product prod = findProduct(name);
return prod;
}
}
Another CustomerService class use the above ProductManager:
public class CustomerService {
...
public void handleProduct() {
Product appleProd = ProductManager.getProduct("apple");
doHandle(appleProd);
}
}
I unit test handleProduct() method in CustomerService class. I use mockito to mock the ProductManager.getProduct("apple") part in test:
public class CustomerServiceTest {
#Test
public void testHandleProduct() {
Product mockProd = Mockito.mock(Product.class);
// MissingMethodInvocationException
when(ProductManager.getProduct("apple")).thenReturn(mockProd);
...
}
}
However, when I run my test, I got MissingMethodInvocationException from Mockito:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
It complains that inside when() I don't call method, but I do call the public static method ProductManager.getProduct("apple") in when(...), why Mockito rise this error to me ? I don't understand.
Mockito cannot mock static methods. Make it an instance method and your code will work.
There are other frameworks that allow that (e.g. Powermock), however this is rather bad practice and a sign of bad design. You should create an instance and do dependency injection. If a method is so small that it can be tested indirectly while testing other class (e.g. Math.max()), than there is no need for mocking.
In the code you posted you have getProduct(), but in the stack trace it is getArticles() - I assume that the code was just a simplified example, while the stack trace is actual.
Here are a few articles explaining the problem of testing/mocking static methods:
https://softwareengineering.stackexchange.com/questions/231594/mocking-static-methods
http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
http://blog.christianposta.com/testing/java-static-methods-can-be-a-code-smell/
Why does Mockito not mock static methods?
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.
I have a class FileGenerator, and I'm writing a test for the generateFile() method that should do the following:
1) it should call the static method getBlockImpl(FileTypeEnum) on BlockAbstractFactory
2) it should populate variable blockList from the subclass method getBlocks()
3) it should call a static method createFile from a final helper class FileHelper passing a String parameter
4) it should call the run method of each BlockController in the blockList
So far, I have this empty method:
public class FileGenerator {
// private fields with Getters and Setters
public void generateBlocks() {
}
}
I am using JUnit, Mockito to mock objects and I've tried using PowerMockito to mock static and final classes (which Mockito doesn't do).
My problem is: my first test (calling method getBlockList() from BlockAbstractFactory) is passing, even though there is no implementation in generateBlocks(). I have implemented the static method in BlockAbstractFactory (returning null, so far), to avoid Eclipse syntax errors.
How can I test if the static method is called within fileGerator.generateBlocks()?
Here's my Test Class, so far:
#RunWith(PowerMockRunner.class)
public class testFileGenerator {
FileGenerator fileGenerator = new FileGenerator();
#Test
public void shouldCallGetBlockList() {
fileGenerator.setFileType(FileTypeEnum.SPED_FISCAL);
fileGenerator.generateBlocks();
PowerMockito.mockStatic(BlockAbstractFactory.class);
PowerMockito.verifyStatic();
BlockAbstractFactory.getBlockImpl(fileGenerator.getFileType());
}
}
I have no experience with PowerMock, but since you didn't get an answer yet I'm just been reading through the documentation to see if I can help you a bit on your way.
I found that you need to prepare PowerMock so that I knows which static methods it needs to prepare to be mocked. Like so:
#RunWith(PowerMockRunner.class)
#PrepareForTest(BlockAbstractFactory.class) // <<=== Like that
public class testFileGenerator {
// rest of you class
}
Here you can find more information.
Does that help?
Working example:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassStaticA.class, ClassStaticB.class})
public class ClassStaticMethodsTest {
#Test
public void testMockStaticMethod() {
PowerMock.mockStatic(ClassStaticA.class);
EasyMock.expect(ClassStaticA.getMessageStaticMethod()).andReturn("mocked message");
PowerMock.replay(ClassStaticA.class);
assertEquals("mocked message", ClassStaticA.getMessageStaticMethod());
}
I'm having some difficulty with EasyMock (3.1) class mocking. This is supposedly suitable to mock partial class implementations, which, I figured, should be ideal to unit test abstract base classes while mocking out the missing method(s). Here's the pattern - an instantly recognizable classic...
public interface Interface {
public void intfMethod();
}
public abstract class AbstractBase implements Interface {
public void otherMethod() {
// do some stuff we need to test...
intfMethod();
}
}
Now the test:
public class TestAbstractBase {
AbstractBase testInstance;
#Before
public void setUp() {
testInstance =
createMockBuilder(AbstractBase.class).addMockedMethod("intfMethod").createMock();
}
#Test
public void testOtherMethod() {
testInstance.intfMethod(); // expect this to be invoked on the mock...
replay(testInstance);
testInstance.otherMethod();
verify(testInstance);
}
}
EasyMock doesn't seem to like this. It throws:
java.lang.IllegalArgumentException: Method not found (or private): intfMethod
at org.easymock.internal.MockBuilder.addMockedMethod(MockBuilder.java:78)
at TestAbstractBase.setUp(TestAbstractBase.java:19)
Any ideas? I found a related question but it doesn't really do justice to its title...
Many thanks to #nhaldimann ; I'd overlooked this innocuous statement in the doc, namely that "abstract methods are conveniently mocked by default". So all the above needs is to remove the attempt to explicitly mock the interface method, as in:
testInstance = createMockBuilder(AbstractBase.class).createMock();
While researching this, I came across two other workarounds - although the above is obviously preferable:
Use the stronger addMockedMethod(Method) API, as in:
public void setUp() throws Exception {
Method m = AbstractBase.class.getMethod("intfMethod");
testInstance = createMockBuilder(AbstractBase.class).addMockedMethod(m).createMock();
}
Explicitly expose the intfMethod method in AbstractBase
These two workarounds suggest that my initial issue is a bit of a bug on the EasyMock side of things. But since there's no need to mock that method in the first instance, we'll say this is "user (my) error".
mockito-version: 1.9.0
I want to setup a call to a method of a mocked object in mockito without calling the original method itself:
EDIT: this example actually works as expect, i.e. the body method "test()" of does not get executed. However, after further investigation I noticed that the original method had the default visibility modifier and I suspect this to cause problems since after changing it to public (shouldn't this be the same?!) it works as expected.
e.g.
public class TestClass {
public String test() {
System.out.println("test called!");
return "test";
}
}
//in test
TestClass mock = mock(TestClass.class);
when(mock.test()).thenReturn("mock!"); //<-- prints test called here? why? how can I switch it off?
The following, running under Mockito 1.9.0 and JUnit 4.8.2, does not print anything to my console:
import static org.mockito.Mockito.*;
import org.junit.Test;
public class TestNonCall {
public class TestClass {
public String test() {
System.out.println("test called!");
return "test";
}
}
#Test
public void doTest() {
final TestClass mock = mock(TestClass.class);
when(mock.test()).thenReturn("mock!");
}
}
Further, if I put a breakpoint in the test() method it is never hit.
Perhaps post more code? It looks like your example is not complex enough to demonstrate the behaviour you're having problems with.
Also: are you using the latest version of Mockito?
Edit: New Thought: Are You Mocking a Final Method?
If you add a final modifier to the method you are mocking, you get the behaviour you reported.
This is because Mockito does not mock final and static methods. Instead, it delegates the calls to the real implementation.
Might your actual code be attempting to mock a final method?
If so, you can use PowerMock, which is an extension to Mockito that allows mocking final methods.
You would need to add the following annotations to your test case class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(TestClass.class)
public class TestNonCall {
// ...
}
and mock the class using the PowerMock method in your test method:
final TestClass mock = PowerMockito.mock(TestClass.class);
then proceed as usual.
I have this Mockito code:
interface Dao {
public void doSomething();
}
class LegacyClass {
Dao dao;
public String legacyMethod() {
dao.doSomething();
return "Test";
}
}
public class MockitoTest {
public static void main(String[] args) {
Dao dao = mock(Dao.class);
LegacyClass legacyInst = new LegacyClass();
legacyInst.dao = dao;
LegacyClass legacy = spy(legacyInst);
when(legacy.legacyMethod()).thenReturn("Replacement");
}
}
The last when() throws the following exception:
Exception in thread "main" org.mockito.exceptions.base.MockitoException:
'doSomething' is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
doThrow(exception).when(mock).someVoidMethod();
If the method you are trying to stub is *overloaded* then make sure you are calling the right overloaded version.
at mypkg.MockitoTest.main(MockitoTest.java:28)
However, I am NOT mocking return value for Dao.doSomething, but for LegacyClass.legacyMethod().
Is this the expected behavior? Are there any Mockito docs stating you cannot nest mocks like this?
How can I walk this around?
Spies don't work this way. In your sample code, the real method legacy.legacyMethod() is actually called because it's a spy not a mock (which then calls dao.doSomething()), that's why you are getting this error.
If you want to make a partial mock, you have to write this as :
doReturn("Replacement").when(legacy).legacyMethod();
That way Mockito will know that you want to make a partial mock, so it won't call the real method.