Nested mocking in Mockito - java

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.

Related

Mocking a method in a class dynamically

I am pretty new to Mockito and Spring.
I am trying to mock many methods of many classes. I want to create a functionality where bean name and method name can given as input as string, and it will throw same exception.
Example
I have a class A and Class B
#Named
public Class A {
public void methodInA() {
System.out.println("In A");
}
}
#Named
public Class B {
public void methodInB() {
System.out.println("In B");
}
}
Below is what I am trying to do in test.
TestConfig:
#SpyBean
A a;
Test::
String className = "A";
String methodName = "methodInA";
Object bean = applicationContext.getBean("a");
Class clazzToSpy = bean.getClass();
Class[] paramTypes = clazzToSpy.getMethod(methodName);
Answer answer = new Answer() {
#Override
public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
if(invocationOnMock.getMethod().getName().equals(methodName)) {
throw new UnknownError("Manual Exception Created");
}
return invocationOnMock.callRealMethod();
}
};
//Here I want to use the answer on the mock Something like below.
Method mockedMethod = clazzToSpy.getMethod(methodName, paramTypes);
Mockito.doAnswer(answer).when(mockedMethod)
I understand there is a gap in my understanding.
How do I achieve something like above?
Has someone tried doing similar thing?
Related threads which I have tried:
Mocking Reflection based calls
Mocking getClass method with PowerMockito
mockito : mock method call with parameters by reflection
Mockito: is it possible to combine mock with a method name to create a methodCall inside a when() call?
Using Mockito to mock methods by reflection
This seems not going to work since when you:
#Spy
Method methodSpy;
Mockito throws:
org.mockito.exceptions.base.MockitoException: Unable to initialize #Spy annotated field 'methodSpy'.
Please ensure that the type 'Method' has a no-arg constructor.
and if you:
#Mock
Method methodMock;
it throws:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.reflect.Method
Mockito cannot mock/spy because :
- final class
at:
MockitoAnnotations.initMocks( this );

How do I mock call method from testable class?

Want to ask you a question.
How should I properly return some data from method called from testable class ?
For example I have next structure:
Class SomeClass {
public void method1(){
//some logic here
List<Object> howToReturnHereValues = gatData();
//some logic here
}
public List<Object> getData(){
return List<Object>;
}
}
Right now I want to test method1(), but I don't know how to mock call getData() which returns List<Object>.
Any advice please ?
You can do this using a spy, like explained here: https://static.javadoc.io/org.mockito/mockito-core/2.7.17/org/mockito/Mockito.html#13
Example:
#Test
public void testMethod1() throws Exception {
SomeClass someClass = new SomeClass();
SomeClass spy = Mockito.spy(someClass);
Mockito.when(spy.getData()).thenReturn(Arrays.asList("blaat", "blabla"));
spy.method1();
}
This will return a List of "blaat" and "blabla" which can be used by the logic in your method1.
Right now I want to test method1(), but I don't know how to mock call
getData() which returns List.
It is rather a bad idea to mock a public method of a class that is under test.
A unit test should test a behavior and mock dependencies. Here, you unit test only a part of the behavior as you mock the behavior of the tested class.
If the class is ours you could :
either test this method without mocking the getData() called public method.
or move the getData() public method in another class and then mock this new dependency if you don't want to repeat the test of the getData() method in each test method calling it.
If the class is not modifiable and the mocked called is really required, you could use the spy() method of the Mockito framework on the object under test to simulate a mocked behavior for a specific method.

MissingMethodInvocationException from Mockito when do unit test

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?

EasyMock - mocking abstract methods inherited from an interface

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".

how to setup a call to method of mocked object in mockito without calling the original method itself

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.

Categories

Resources