Need advice on unit testing with suppressing submethods and constructors - java

I have some weird code like this
B param = ...;
D main(){
return A.method(param, C.class, new String[]{"abc"}, new SomeClass()).get();
}
where
public static A method(...)
public D get()
How can I mock method main() to suppress submethods invocations and suppress constructing of objects?
I need to mock result of get()

Aside from a better designed method that injects instances into the method instead of create them, you can use Powermock to mock constructor calls so the calls to new will actually create mock objects.
here is powermock's tutorial on mock constructors with mockitto
http://code.google.com/p/powermock/wiki/MockitoUsage13
IN your test you will be able to say:
SomeClass myMock = mock(SomeClass.class);
whenNew(SomeClass.class).withNoArguments().thenReturn(myMock)

Related

Spring Mockito Mocked object keeps calling real method [duplicate]

I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.

Can we mock 2nd object creation using powermock

We can mock the object creation using powermock using below line:
MyClass myObj = getMyObj();
PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(myObj);
Now in my class where I am writing test case, I have logic of this kind:
public class TestClass {
public void testMethod() {
MyClass obj = new MyClass();
boolean flag = doSomeOperation();
if(flag) {
MyClass obj1 = new MyClass();
//doSomeOtherOp();
}
}
}
Here I want to mock the second object creation obj1, is it possible with powermock to control which object I want to mock. Here I don't want to mock the 1st object obj.
I thought this to be simple:
PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(firstResult)
.thenReturn(anotherResult);
but unfortunately, although chaining is possible in other contexts, it seems that PowerMockito doesn't allow for it.
( Something like
when(someMock.toString()).thenReturn("a").thenReturn("b");
System.out.println(someMock.toString() +factory.toString();
just nicely prints ab ! )
So the only answer I can give right now: you wrote hard to test code. Consider not doing that.
Instead of relying on PowerMock to mock calls to new() you should rather step back and change your design. For example by using a factory in your production code. So instead of calling new() directly, you simply ask the factory for new instances. And that factory can be easily mocked without the need of PowerMock(ito).

Mockito - mock subclass method call

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.

Cannot Mockito spy class in Spock test?

I'm trying to spy a Java class in a Spock test. I've not had a problem with Mockito in Spock/Groovy before.
When I try to do the following:
def service = spy(Service.class)
I get the following error:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.Class
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
When I do mock(Service.class) though, it works fine.
I have confirmed that the class is not final, anonymous, or primitive.
Any ideas? I have a random generator in the class (ak) so I need to spy not mock.
Thank you
Mockito doesn't spy on Classes (or Mocks), it spies on (regular) Objects. Thus, instead of
def service = spy(Service.class)
you have to write
def service = spy(new Service())
(or whichever constructor is appropriate for your scenario).
Just an extra to Ray's answer, you can also spy on already created instances. The only thing is that all methods you called before spy() was called, cannot be verified. Like:
ClassToSpy spiedInstance;
#Before
public void before () {
spiedInstance = new ClassToSpy();
}
#Test
public void testWillFail() {
spiedInstance.method();
spiedInstance = spy(spiedInstance);
verify(spiedInstance).method();
}
#Test
public void testWillPass() {
spiedInstance = spy(spiedInstance);
spiedInstance.method();
verify(spiedInstance).method();
}
The error you would get from testWillFail would be similar to:
Wanted but not invoked:
classToSpy.method();
-> at your.package.testWillFail(TestClass.java:line)
Actually, there were zero interactions with this mock.
Due to the fact that, after spied, you did not call this method.

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