Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to mock static system class with PowerMock gives VerifyError

I am trying to mock JOptionPane static methods, and am stuck at a Java.lang.VerifyError. All versions are current, since I just downloaded PowerMock for Mockito, and all their dependencies.

I cannot use the answer given for a previous question, to wrap the class and subclass the wrapper - this is all over our application. I've invested a fair amount of time in PowerMock at this point, and I don't want to start over with fest.

Is there a way to resolve this error? I've tried both "Mocking Static Methods" and "Mocking System Classes" in the instructions. I can't go any farther since all I've done is @RunWith(PowerMockRunner.class) and @PrepareForTest(My.class).

I found that I could reduce this to an issue with any reference to a class that extends JPanel. Here is a minimum test to create the issue (I've gotten the same exception with PrepareForTest on Boffo and on JPanel):

import javax.swing.JPanel;
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(JPanel.class)
@PrepareForTest(TestCase.Boffo.class)
public class TestCase {

    @SuppressWarnings("serial")
    public static class Boffo extends JPanel {}

    @Test
    public void test() throws Exception {
        new Boffo();
    }
}

Here is the exception I get when I try to run the test:

java.lang.VerifyError: (class: javax/swing/plaf/metal/MetalLookAndFeel, method: getLayoutStyle signature: ()Ljavax/swing/LayoutStyle;) Wrong return type in function
    at javax.swing.UIManager.setLookAndFeel(Unknown Source)
    at javax.swing.UIManager.initializeDefaultLAF(Unknown Source)
    at javax.swing.UIManager.initialize(Unknown Source)
    at javax.swing.UIManager.maybeInitialize(Unknown Source)
    at javax.swing.UIManager.getUI(Unknown Source)
    at javax.swing.JPanel.updateUI(Unknown Source)
    at javax.swing.JPanel.<init>(Unknown Source)
    at javax.swing.JPanel.<init>(Unknown Source)
    at javax.swing.JPanel.<init>(Unknown Source)
    at com.package.TestCase$Boffo.<init>(TestCase.java:17)
    at com.package.TestCase.test(TestCase.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:42)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
like image 458
orbfish Avatar asked Aug 13 '12 23:08

orbfish


Video Answer


2 Answers

Here's a neat workaround/solution that a colleague of mine discovered today: Just add the annotation @PowerMockIgnore("javax.swing.*") to the test class and PowerMock will defer the loading of the problematic classes to the system classloader.

edit: Just re-read the question and since you're trying to mock JOptionPane itself I'm not sure this will help, but maybe you can play around with the exclusions pattern.

like image 125
Matthew Wise Avatar answered Dec 10 '22 01:12

Matthew Wise


I have no idea actually why it throws VerifyError, but you can overcome it by setting a fake LookAndFill in advance before instantiating the class.

public static class FakeLookAndFill extends BasicLookAndFeel {
    @Override
    public String getName() {
        return "FakeLookAndFill";
    }

    @Override
    public String getID() {
        return "FakeLookAndFill";
    }

    @Override
    public String getDescription() {
        return "FakeLookAndFill";
    }

    @Override
    public boolean isNativeLookAndFeel() {
        return false;
    }

    @Override
    public boolean isSupportedLookAndFeel() {
        //note it returns true
        return true;
    }
}

@Before
public void setUp() throws Exception {
    UIManager.setLookAndFeel(new FakeLookAndFill());
}
like image 44
denis.solonenko Avatar answered Dec 09 '22 23:12

denis.solonenko