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().
Related
I am attempting to Junit test (IDE: Intellij) Method inside a class called "ManagementDashboardBean" called: (Method name): init()
The method contains FaceContext and Session. I tried the following: https://codenotfound.com/mockito-unit-testing-facescontext-powermock-junit.html
but am still running into issues. I am using Mockito and PowerMockito to help but cannot figure out my init() is saying Null Pointer Exception (NPE). Any guidance would be greatly appreciated. Thanks
P.S the end goal is to show proper test code coverage of this method.
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(false);
userInfo = (UserSessionInfo)session.getAttribute(ConstantsUtil.USER_INFO);
startDt = FDUtil.toDate(FDUtil.toStartOfMonth(userInfo.getCurrentDateMillis()));
endDt = FDUtil.toDate(FDUtil.toEndOfMonth(userInfo.getCurrentDateMillis()));
autoCompleteDate = false;
}
Current JUnit Test
package view.managed.core;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import com.sun.jdi.connect.Connector;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({FacesContext.class})
public class ManagementDashboardBeanTest {
private ManagementDashboardBean someBean;
#Mock
private FacesContext facesContext;
#Mock
private ExternalContext externalContext;
#Before
public void setUp() throws Exception {
someBean = new ManagementDashboardBean();
//mock all static methods of FaceContext using PowerMockito
PowerMockito.mockStatic(FacesContext.class);
when(FacesContext.getCurrentInstance()).thenReturn(facesContext);
when(facesContext.getExternalContext()).thenReturn(externalContext);
}
#Test
public void testInitContext() {
//create Captor instances for the userInfo
// ArgumentCaptor<String> clientIdCapture = ArgumentCaptor.forClass(String.class);
// ArgumentCaptor<HttpSession> session = ArgumentCaptor.forClass(HttpSession.class);
// Run the method being tested
// someBean.init();
// verify(facesContext).addMessage(clientIdCapture.capture(), (FacesMessage) session.capture());
}
}
The actual .java source file starts with:
public class ManagementDashboardBean extends EntityManagerService implements Serializable {
private static final Logger LOG = LoggerFactory.getLogger(ManagementDashboardBean.class);
The right after is this, which confuses the hell out of me:
public ManagementDashboardBean() {
init();
}
What I have added so far:
import static org.junit.Assert.*;
import javax.faces.context.FacesContext;
import mil.af.fd.view.managed.services.EntityManagerService;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.core.classloader.annotations.PrepareForTest;
import java.io.Serializable;
#RunWith(MockitoJUnitRunner.class)
#PrepareForTest({FacesContext.class})
public class ManagementDashboardBeanTest {
private ManagementDashboardBean dashboard;
private Serializable serializableMock;
private EntityManagerService entityManagerServiceMock;
#BeforeClass
public static void before() {
System.out.println("Before Class");
}
#Before
public void setUp() throws Exception {
entityManagerServiceMock = Mockito.mock(EntityManagerService.class);
serializableMock = Mockito.mock(Serializable.class);
dashboard = new ManagementDashboardBean(serializableMock);
}
#Test
public void testInitContext() {
// dashboard.init();
System.out.println("Test 1");
}
}
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());
}
}
Consider two classes A and B.
class A { static int a(){} }
class B { void something(){ int value=A.a(); .......}}
Now I have to cover class B using Junit Test case and hence I create a new class (class TestB) to cover the class B.
class TestB { #Test public void testsomething(){...} }
Here my question is if there is any way I can cover the line A.a() as this is the static method. I know that I can't easy mock it because there is no object involved. So how would I proceed?
I am using JUnit and EasyMock.
As you pointed out there is no way to mock a static method with easymock.
Approach 1: Don't use static methods wherever possible.
Approach 2: Use PowerMock on top of easymock.
Approach 3: Delegate the body of A.a() by using a supplier inside a(). You can than use a "simple" supplier for testcases and the real world supplier for productive use.
You will have to use PowerMock along with easymock to mock the static methods.
https://github.com/jayway/powermock/wiki/MockStatic
For your test case mock code will look like this
KeyStore aMock = PowerMockito.mock(A.class);
PowerMockito.when(A.a()).thenReturn(0);
Here is a working example to mock static method for KeyStore.getInstance method
KeyStoreService:
package com.foo;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
public class KeyStoreService {
public KeyStoreService(){
}
public void load() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{
System.out.println("start");
KeyStore ks = KeyStore.getInstance("");
ks.load(null, null);
System.out.println("end");
}
}
Test class:
package com.foo.test;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.foo.KeyStoreService;
#PrepareForTest(KeyStoreService.class)
#RunWith(PowerMockRunner.class)
public class TestKeyStore {
#Test
public void test1() throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException{
PowerMockito.mockStatic(KeyStore.class);
KeyStore keyStoreMock = PowerMockito.mock(KeyStore.class);
KeyStoreService kss = new KeyStoreService();
PowerMockito.when(KeyStore.getInstance(Matchers.anyString(), Matchers.anyString())).thenReturn(keyStoreMock);
Mockito.doNothing().when(keyStoreMock).load(Mockito.any(InputStream.class), Mockito.any(char[].class));
kss.load();
}
}
Is it a bug of Powermock or I'm doing sth wrong?
The following test should pass, but failed with:
trackBugPartialMockCountMore(com.xiaomi.finddevice.test.testcase.PowerMockBug)
org.mockito.exceptions.verification.TooManyActualInvocations:
classToMock.foo();
Wanted 1 time:
-> at com.xiaomi.finddevice.test.testcase.PowerMockBug.trackBugPartialMockCountMore(PowerMockBug.java:24)
But was 3 times. Undesired invocation:
-> at com.xiaomi.finddevice.test.testcase.PowerMockBug.trackBugPartialMockCountMore(PowerMockBug.java:22)
When I remove #PrepareForTest(ClassToMock.class), every thing goes well and the test get passed.
import org.junit.Ignore;
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.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassToMock.class)
public class PowerMockBug {
#Test
public void trackBugPartialMockCountMore() {
ClassToMock mock = mock(ClassToMock.class);
when(mock.foo()).thenCallRealMethod();
mock.foo();
verify(mock).foo();
}
}
class ClassToMock {
public int foo() { return 0x10; }
}
VERSION: powermock-mockito-junit-1.6.3
In your example you don't need to use PowerMock because you are not mocking/spying a final or static method. You can safely remove both #RunWith and #PrepareForTest annotations. Only mockito is needed for your purposes
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().