Mockito - mock subclass method call - java

I am working with legacy code and trying to write a unit test for an implementation I did. I have the following structure:
AbstractClass:
----------------
public AbstractClass {
abstract method2();
void method1(){
...does something...
..calls --> method2()
}
}
Subclass
------------
public Subclass extends AbstractClass(){
void method2(){
..do something....
..mockThisMethod()...
return true;
}
}
I have an abstract class which has some logic implemented in a specific method.
This method calls than another method implemented in the subclass. The method in the subclass calls other methods which I want to mock.
Is this possible without changing the implementation code (hard to change)?
Mos of the results are suggesting using mockito spying but it doesn't work.
I followed the TestDesign describer here:
https://www.tildedave.com/2011/03/06/pattern-stubbing-legacy-superclasses-with-mockito-spies.html
What I did is:
Subclass subclass= spy(Subclass.class);
when(subclass.mockThisMethod()).thenReturn(something);
subclass.method1() (I am not sure if this line is correct?)
So what I want to avoid is, calling the method (mockThisMethod) in the Subclass.
Since this method does some db-stuff an so on. I know it would be easier to test, if I use object composition instead of inheritance but at this point, it is hard to change the whole implementation. The code above is not working..I get a NPE.

1) You do not create a Spy by passing the class to the static Mockito.spy method.
Instead, you must pass an instance of that particular class:
Subclass subclassSpy = spy(new Subclass());
Also, consider using annotations:
#Spy
private Subclass subclassSpy = new Sublcass();
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
2) Avoid using when.thenReturn when stubbing a spy.
Instead, use doReturn..when..methodCall:
doReturn(something).when(sublcass).mockThisMethod();
otherwise you will invoke the actual method while stubbing and this may lead to unwanted behavior and/or exceptions.

Related

UnfinishedStubbingException when passing mocked class as an argument in thenThrow

Can I pass mocked object as an argument to thenThrow() method? I have something like this:
public class MyException extends Exception {
public MyException(MockedClass mockedClass) {
super("My message:" + mockedClass.doSth("foo"));
}
}
public class TestedServiceTest {
#Mock
MockedClass mockedClass;
#Mock
AnotherClass anotherClass;
#Before
public void init() {
when(mockedClass.doSth(anyString())).thenAnswer(new Answer<String>() {
#Override
public String answer(InvocationOnMock invocation) throws Throwable {
return invocation.getArgument(0);
}
});
}
#Test
public void notWorkingTestMethod() {
when(anotherClass.doSomething()).thenThrow(new MyException(mockedClass));
}
notWorkingTestMethod() throws org.mockito.exceptions.misusing.UnfinishedStubbingException
However if I use the same technique on void method it doesn't complain anymore:
#Test
public void workingTestMethod() {
doThrow(new MyException(mockedClass)).when(anotherClass).doSomethingVoid();
}
}
Is there any other possible reason it doesn't work?
To understand why this is happening you need to understand a bit about how Mockito works.
Mockito uses internal static state to keep track of what setup is being done to which mocks. This does allow for clear and expressive mocking, but sometimes it does cause a violation of the Principle of Least Astonishment, as it seems you've encountered here.
Let's consider the line in your not-working test method:
when(anotherClass.doSomething()).thenThrow(new MyException(mockedClass));
Mockito sees these interactions, in the following order:
a call to anotherClass.doSomething(), which Mockito will record internally as the last invocation on a mock, because this mock method might be about to be set up to do something.
a call to the static when method, so Mockito knows that the behaviour of anotherClass.doSomething() is being set up.
a call to mockedClass.doSth() in the MyException constructor. This is another invocation on a mock, which Mockito wasn't expecting.
At this point, the doThrow() method hasn't been called, so Mockito can't know that you will later call it to set up the exception to throw. Instead, it looks to Mockito as if you are writing:
when(anotherClass.doSomething());
when(mockedClass.doSth()).then....
Hence the exception about unfinished stubbing.
The fix, as suggested by #marcellorvalle in the comment, is to move the exception out into a local variable:
MyException myException = new MyException(mockedClass);
when(anotherClass.doSomething()).thenThrow(myException);
In most cases, extracting a local variable like this won't change the behaviour of the code. But it does change the order of the three interactions with Mockito I listed above. It is now:
a call to mockedClass.doSth() in the constructor of your exception, which Mockito will record internally as the last invocation on a mock.
a call to anotherClass.doSomething(), which Mockito will record internally as the last invocation on a mock, replacing the previous one.
a call to the static when method, so Mockito knows that the behaviour of anotherClass.doSomething() is being set up.
The next interaction with Mockito is then the call to thenThrow(), which Mockito can then link to the call to anotherClass.doSomething().
As for your workingTestMethod() method, it has the line
doThrow(new MyException(mockedClass)).when(anotherClass).doSomethingVoid();
This mock setup works, because this time, the order of interactions with Mockito is:
a call to mockedClass.doSth() in the constructor of your exception, which Mockito will record internally as the last invocation on a mock. (It happens that in this case, this last-invocation isn't used.)
a call to the static doThrow() method. At this point, Mockito doesn't know what mock or what method to throw the exception for, so it can only make a note of the exception.
a call to the when method on the Stubber instance that doThrow() returns. This tells Mockito which mock is being set up, and also to watch out for whatever the next invocation of a mock method is, as that is what is being set up. It looks like this when method returns the mock that it is given.
a call to the doSomethingVoid() method of your mock. Mockito can then link the exception that was to be thrown to this method.

Is it possible to use JMockit's Deencapsulation API to exchange method implementation?

So, basically, a there is some poor code that I cannot change that needs to be tested. Traditionally, you inject your mocked dependencies, but with this code, I cannot do so, because there are no setter methods. Worse, the function I need to test calls a bunch of static factory methods-I can't just use the MockUp strategy to swap out the implementation there, because there is no class instance to be injected at all.
In C/++, you can retrieve a pointer to a function and know it's type by it's signature. If you changed the pointer, then you could potentially change how the stack was constructed by the compiler and you could pass function's around and all that Jazz.
Is there a way to use the Deencapsulation API to replace a static method implementation? Using this, I could write my own class, descend from the traditional, but return mocked objects in order that dependency injection still be achieved?
public class TestedClass {
public static void testedMethod() {
UnMockableType instanceVariable =
UnInjectableFactory.staticFactoryConstructor();
instanceVariable.preventControlFlowInfluenceThroughMocking();
}
}
Easy enough:
#Test
public void exampleTestUsingAMockUp()
{
new MockUp<UnMockableType>() {
#Mock
void preventControlFlowInfluenceThroughMocking() {}
};
TestedClass.testedMethod();
}
Above, UnInjectableFactory isn't mocked because it doesn't need to be (assuming it simply instantiates/recovers an UnMockableType).
It could also be done with #Mocked and the Expectations API.

How to mock static methods using UnitilsJUnit4?

I have method getAllCustomers inside CustomerService class. Inside this method I call another static method from CustomerDao class.
Now when I am writing the junit for method getAllCustomers inside customerService class, where I want to mock the call to
static method of CustomerDao i.e. getAllCustomers. Here is the brief code snippet of method getAllCustomers inside
CustomerService class. Is it possible to mock the static method call using unitils?
Public static List<CustomerDate> getAllCustomers()
{
//some operations
List<CustomerDate> customers=CustomerDao.getAllCustomers();// static method inside CustomerDao
//some operations
}
Above code is just an example I am trying to put. Please avoid the discussion why these methods are designed as static
methods. That's a separate story .)
I doubt whether it can be achieved with unitils.
But please consider using PowerMock instead which seems to be capable of handling what you need. It can mock static methods,private methods and more (Ref: PowerMock)
This would be a matter of:
Setting up the mock
Calling the mock and expecting some data back
Verifying the end result of your call given your data
So, without really much ado about the static call, here's the way you can set it up in PowerMock:
#RunWith(PowerMockRunner.class)
#PrepareForTest(CustomerDao.class)
public class CustomerTest {
#Test
public void testCustomerDao() {
PowerMock.mockStatic(CustomerDao.class);
List<CustomerDate> expected = new ArrayList<CustomerDate>();
// place a given data value into your list to be asserted on later
expect(CustomerDao.getAllCustomers()).andReturn(expected);
replay(CustomerDao.class);
// call your method from here
verify(CustomerDao.class);
// assert expected results here
}
}

Mockito - deep stubbing

I am using Mockito to test my classes. I am trying to use Deep stubbing as I didn't a way on injecting a Mock inside another mock object in Mockito.
class MyService{
#Resource
SomeHelper somehelper;
public void create()
{
//....
somehelper.invokeMeth(t);
}
}
class SomeHelper{
#Resource
private WebServiceTemplate webServiceTemplate;
public void invokeMeth(T t)
{
try{
//...
webServiceTemplate.marshalSendAndReceive(t);
}catch (final WebServiceIOException e) {
throw new MyAppException("Service not running");
}
}
}
Now I am trying to Unit test the MyService class's create() method.
I have injected a mock for SomeHelper as follows
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeHelper somehelper;
What I want now is when the invokeMeth() method gets called on the mocked somehelper object it calls the real method in this case.
when(somehelper.invokeMeth(isA(RequestObject.class)))
.thenCallRealMethod();
I was expecting the webServiceTemplate not be null in this case.
However I get a Nullpointer exception when the code tries to execute the line
webServiceTemplate.marshalSendAndReceive(t);
Any clue how I can get access to a deep mock object (i.e. mock within a mock - in this case webserviceTemplete mock inside somehelper mock) and then apply a when condition to throw a WebserviceIOException ?
I want this so that I can test the MyService.create() to check it behaves properly when a WebServiceIOException is thrown down the code.
Yes of course, you are mixing real objects and mocks. Plus using the thenCallRealMethod lloks like a partial mock, it feels wrong here, it's no wonder the javadoc of this method talks about that as well.
I definatelty should stress you than, design wise, having a mock that returns a mock is often a smell. More precisely you are breaking the Demeter Law, or not following the Tell, Don't Ask principle.
Any looking at your code I don't why the code would need to mock WebServiceTemplate. You want to unit test MyService, and I don't see a relationship to WebServiceTemplate. Instead you should focus on the interactions with you helper only. And unit test SomeHelper separately where you'll be able to check the interactions between SomeHelper and WebServiceTemplate.
Here's a little example of how I see the thing:
public void ensure_helper_is_used_to_invoke_a_RequestObject() {
// given a service that has an helper collaborator
... other fixture if necessary
// when
myService.behaviorToTest();
// then
verify(someHelperMock).invokeMeth(isA(RequestObject.class));
}
How those that look for your real use case ?
Hope that helps

Mockito: Trying to spy on method is calling the original method

I'm using Mockito 1.9.0. I want mock the behaviour for a single method of a class in a JUnit test, so I have
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
The problem is, in the second line, myClassSpy.method1() is actually getting called, resulting in an exception. The only reason I'm using mocks is so that later, whenever myClassSpy.method1() is called, the real method won't be called and the myResults object will be returned.
MyClass is an interface and myInstance is an implementation of that, if that matters.
What do I need to do to correct this spying behaviour?
Let me quote the official documentation:
Important gotcha on spying real objects!
Sometimes it's impossible to use when(Object) for stubbing spies. Example:
List list = new LinkedList();
List spy = spy(list);
// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
In your case it goes something like:
doReturn(resultsIWant).when(myClassSpy).method1();
In my case, using Mockito 2.0, I had to change all the any() parameters to nullable() in order to stub the real call.
My case was different from the accepted answer. I was trying to mock a package-private method for an instance that did not live in that package
package common;
public class AnimalĀ {
void packageProtected();
}
package instances;
class Dog extends Animal { }
and the test classes
package common;
public abstract class AnimalTest<T extends Animal> {
#Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
#Test
public void myTest(){}
}
The compilation is correct, but when it tries to setup the test, it invokes the real method instead.
Declaring the method protected or public fixes the issue, tho it's not a clean solution.
The answer by Tomasz Nurkiewicz appears not to tell the whole story!
NB Mockito version: 1.10.19.
I am very much a Mockito newb, so can't explain the following behaviour: if there's an expert out there who can improve this answer, please feel free.
The method in question here, getContentStringValue, is NOT final and NOT static.
This line does call the original method getContentStringValue:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
This line does not call the original method getContentStringValue:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
For reasons which I can't answer, using isA() causes the intended (?) "do not call method" behaviour of doReturn to fail.
Let's look at the method signatures involved here: they are both static methods of Matchers. Both are said by the Javadoc to return null, which is a little difficult to get your head around in itself. Presumably the Class object passed as the parameter is examined but the result either never calculated or discarded. Given that null can stand for any class and that you are hoping for the mocked method not to be called, couldn't the signatures of isA( ... ) and any( ... ) just return null rather than a generic parameter* <T>?
Anyway:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
The API documentation does not give any clue about this. It also seems to say the need for such "do not call method" behaviour is "very rare". Personally I use this technique all the time: typically I find that mocking involves a few lines which "set the scene" ... followed by calling a method which then "plays out" the scene in the mock context which you have staged... and while you are setting up the scenery and the props the last thing you want is for the actors to enter stage left and start acting their hearts out...
But this is way beyond my pay grade... I invite explanations from any passing Mockito high priests...
* is "generic parameter" the right term?
One more possible scenario which may causing issues with spies is when you're testing spring beans (with spring test framework) or some other framework that is proxing your objects during test.
Example
#Autowired
private MonitoringDocumentsRepository repository
void test(){
repository = Mockito.spy(repository)
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
In above code both Spring and Mockito will try to proxy your MonitoringDocumentsRepository object, but Spring will be first, which will cause real call of findMonitoringDocuments method. If we debug our code just after putting a spy on repository object it will look like this inside debugger:
repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$
#SpyBean to the rescue
If instead #Autowired annotation we use #SpyBean annotation, we will solve above problem, the SpyBean annotation will also inject repository object but it will be firstly proxied by Mockito and will look like this inside debugger
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
and here is the code:
#SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
Important gotcha on spying real objects
When stubbing a method using spies , please use doReturn() family of methods.
when(Object) would result in calling the actual method that can throw exceptions.
List spy = spy(new LinkedList());
//Incorrect , spy.get() will throw IndexOutOfBoundsException
when(spy.get(0)).thenReturn("foo");
//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
I've found yet another reason for spy to call the original method.
Someone had the idea to mock a final class, and found about MockMaker:
As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line: mock-maker-inline
Source: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
After I merged and brought that file to my machine, my tests failed.
I just had to remove the line (or the file), and spy() worked.
One way to make sure a method from a class is not called is to override the method with a dummy.
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
#Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
As mentioned in some of the comments, my method was "static" (though being called on by an instance of the class)
public class A {
static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static
Work around was make an instance method or upgrade Mockito to a newer version with some config: https://stackoverflow.com/a/62860455/32453
Bit late to the party but above solutions did not work for me , so sharing my 0.02$
Mokcito version: 1.10.19
MyClass.java
private int handleAction(List<String> argList, String action)
Test.java
MyClass spy = PowerMockito.spy(new MyClass());
Following did NOT work for me (actual method was being called):
1.
doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());
2.
doReturn(0).when(spy , "handleAction", any(), anyString());
3.
doReturn(0).when(spy , "handleAction", null, null);
Following WORKED:
doReturn(0).when(spy , "handleAction", any(List.class), anyString());

Categories

Resources