How can I mock nested static methods using PowerMockito?
The following is a very simple example on how I want to use it.
Class:
public class SomeClass {
public static String someMethodA(){
//some very important codes here
return someMethodB();
}
private static String someMethodB(){
return someMethodC();
}
private static String someMethodC(){
return "Some Text";
}
}
Already tried the following but did not work:
PowerMockito.mockStatic(SomeClass.class);
PowerMockito.stub(PowerMockito.method(SomeClass.class, "someMethodB")).toReturn("Some Other Text");
I wanted to run someMethodA() as is, which is why I want to stub someMethodB() instead. Is there anyway I can do this? Hoping that there is a way without having to modify the access modifiers because the codes I am working with are legacy codes.
You can spy the private static methods.
Tested in JUnit4
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(SomeClass.class)
public class SomeClassTest {
#Test
public void test() throws Exception {
spy(SomeClass.class);
when(SomeClass.class, "someMethodB").thenReturn("Some Other Text");
assertEquals("Some Other Text", SomeClass.someMethodA());
}
}
Related
Why do I get a NullPointerExeption for testManuscript when trying to run my test?
This is my Manuscript.java:
package org.lhoffjann;
public class Manuscript {
private String msID;
private String path;
public void setMSid(String msID){
this.msID = msID;
}
public String getMSid() {
return this.msID;
}
}
This is my ManuscriptTest.java:
package org.lhoffjann;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ManuscriptTest {
private static Manuscript testManuscript;
#Before
public void setUp(){
testManuscript = new Manuscript();
}
#Test
public void testGetMSid() {
testManuscript.setMSid("1234");
assertTrue("1234" == testManuscript.getMSid());
}
}
You have imported #Test from JUnit 5, while you're using #Before from JUnit 4, that combination doesn't work. You need to choose which JUnit version you want to use, 4 or 5, and then consistently import classes from that JUnit version. I would recommend using JUnit 5, and removing all JUnit 4 dependencies from your classpath, or at least configure your IDE to not suggest those imports.
For this specific case, replace #Before (org.junit.Before) with #BeforeEach (org.junit.jupiter.api.BeforeEach).
In the example as shown, you don't even need this setUp method, as each test-execution gets its own instance of the test class. You can use:
private Manuscript testManuscript = new Manuscript();
That is, remove static, initialize the field directly, and remove the setUp method.
Even if you continue to use the setUp method, I recommend removing the static, so testManuscript is an instance field, like it is actually used.
You have mixed Junit4 with Junit5. You should use only one version.
Junit4 or
package org.lhoffjann;
import org.junit.Before;
import org.junit.Test;
import org.junit.Assert;
public class ManuscriptTest {
private static Manuscript testManuscript;
#Before
public void setUp(){
testManuscript = new Manuscript();
}
#Test
public void testGetMSid() {
testManuscript.setMSid("1234");
Assert.assertEquals("1234",testManuscript.getMSid());
}
or
Junit5
package org.lhoffjann;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ManuscriptTest {
private static Manuscript testManuscript;
#BeforeEach
public void setUp() {
testManuscript = new Manuscript();
}
#Test
void testGetMSid() {
testManuscript.setMSid("1234");
Assertions.assertEquals("1234", testManuscript.getMSid());
}
}
I want to test the following example code:
public class Example {
...
public void doStuff() {
...
Lift lift = new Lift();
lift.call(5);
...
}
...
}
How can I 'intercept' lift.call(5)?
Generally I would use when(lift.call(anyInt()).thenReturn(...), but I have no reference to the Lift object.
You can't do it with mockito alone. The cleanest solution is to refactor your code so you can have access to it. However if that's not an option then "power mockito" is what you want. Grab "powermock-api-mockito"+"powermock-module-junit4" and then something like this will do the trick:
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Example.class)
public class ExampleTest {
private Example testSubject;
#Mock
private Lift lift;
#Test
public void testDoStuff() throws Exception {
testSubject.doStuff();
verify(lift).call(5);
}
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.whenNew(Lift.class).withNoArguments().thenReturn(lift);
testSubject = new Example();
}
}
Can you modify the Example class? If yes, the simplest way would be to extract the Lift dependency and provide it via constructor. Like this:
public class Example {
private final Lift lift;
public Example(Lift lift) {
this.lift = lift;
}
public void doStuff() {
this.lift.call(5);
}
}
Then you can stub lift as you want since now you have access to the instance.
I have a class where I'm using Powermock + Mockito to suppress a static method in a utility class. It works fine with Powermock 1.6.2 and Mockito 1.10.19, but I've been tasked with moving to Java 10 (JRE: we're still compiling with Java 8) and so I've moved to Powermock 2 (currently in beta) and Mockito 2.16.1. Now, I consistently get org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here.
A simple example, MyMockito.java:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.lang.reflect.Method;
import static org.mockito.Mockito.any;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;
#RunWith(PowerMockRunner.class)
#PrepareForTest(StringMeasurer.class)
public class MyMockito {
#Test
public void testSuppressMethod() throws Exception {
spy(StringMeasurer.class);
Method measure = method(StringMeasurer.class, "measure", String.class);
suppress(measure);
when(StringMeasurer.class, measure)
.withArguments(any(String.class))
.thenReturn(10);
System.out.println(StringMeasurer.measure("Hello"));
}
And StringMeasurer.java:
public class StringMeasurer {
private StringMeasurer() {}
public static int measure(String s) {
return s.length();
}
}
}
I'm assuming that either there have been some changes to how matchers can be used to match arguments in stubbed static methods, or else this should never have worked and somehow got through in Mockito 2 (or possibly this is a bug in the Powermock beta). Can anyone provide me some insight into what I'm doing wrong?
Working solution for PowerMock 2.0.0-beta.5:
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(StringMeasurer.class)
public class MyMockito {
#Test
public void testSuppressMethod() throws Exception {
PowerMockito.mockStatic(StringMeasurer.class);
when(StringMeasurer.measure(any(String.class))).thenReturn(10);
System.out.println(StringMeasurer.measure("Hello"));
}
}
More details can be found in the official PowerMock documentation: Mocking Static Method
The question uses the PowerMockito.spy() method, which is required for partial mocking, although the example given only has one static method, so that's not necessary here. Here's a working solution that uses partial mocking for an extended example:
MyMockito.java:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.lang.reflect.Method;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.*;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;
#RunWith(PowerMockRunner.class)
#PrepareForTest(StringMeasurer.class)
public class MyMockito {
#Test
public void testSuppressMethod() throws Exception {
spy(StringMeasurer.class);
Method measure = method(StringMeasurer.class, "measure", String.class);
doReturn(10).when(StringMeasurer.class, measure)
.withArguments(any(String.class));
System.out.println(StringMeasurer.measure("Hello"));
List<String> dummy = StringMeasurer.dummy(5);
assertEquals(5, dummy.size());
dummy.forEach(System.out::println);
}
}
And StringMeasurer.java:
import java.util.ArrayList;
import java.util.List;
public class StringMeasurer {
private StringMeasurer() {}
public static int measure(String s) {
return s.length();
}
public static List<String> dummy(int size) {
List<String> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add("" + i);
}
return list;
}
}
Note that, in this case, the accepted solution would mock the StringMeasurer.dummy() method as well, returning an empty list, and the test would fail on the assertEquals().
I have a final class as below
public class firstclass{
private String firstmethod(){
return new secondclass("params").somemethod();
}
}
public final class secondclass{
secondclass(String params){
//some code
}
public String somemethod(){
// some code
return somevariable";
}
}
I have to here test first class so I have mocked this as below
secondclass classMock = PowerMockito.mock(secondclass .class);
PowerMockito.whenNew(secondclass .class).withAnyArguments().thenReturn(classMock);
Mockito.doReturn("test").when(classMock).somemethod();
But it is not mocking as I expected can anyone help me?
The method firstclass.firstmethod() is private method. So try to test this method through public method in which it is getting called.
You can mock SecondClass and its final method using #RunWith(PowerMockRunner.class) and #PrepareForTest(SecondClass.class) annotations.
Please see below the working code:
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(SecondClass.class)
public class FirstClassTest{
#Before
public void init() {
}
#After
public void clear() {
}
#Test
public void testfirstmethod() throws Exception{
SecondClass classMock = PowerMockito.mock(SecondClass.class);
PowerMockito.whenNew(SecondClass.class).withAnyArguments().thenReturn(classMock);
Mockito.doReturn("test").when(classMock).somemethod();
new FirstClass().firstmethod();
}
}
Libraries used:
MyClass.java:
package test;
public final class MyClass {
public MyClass() { }
public Package returnPackage() {
return MyClass.class.getPackage();
}
}
TestClass.java:
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class TestClass {
#Test
public void test() throws Exception {
System.out.println(new MyClass().returnPackage());
mockStatic(MyClass.class);
System.out.println(new MyClass().returnPackage());
}
}
However, this results in:
package test
null
Any MyClass.class method call returns null after PowerMockito.mockStatic(Class). Is there any way to prevent this?
Workaround: I can use the EasyMock-API to set up the static mocks without PowerMockito.mockStatic().