PowerMock with EasyMock can only mock final classes in the java.* space?

855 views
Skip to first unread message

Scott DeWitt

unread,
Mar 17, 2016, 12:27:13 AM3/17/16
to PowerMock
Hello,

I am trying to mock a final class using PowerMock and EasyMock.  The class I am mocking is a third-party one (not a JRE one inside java.* namespace).  When I try mocking it I get the same as with Easy Mock:

java.lang.IllegalArgumentException: Cannot subclass final class class com.github.fge.jsonschema.main.JsonSchemaFactory
    at org.easymock.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at org.easymock.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.easymock.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.easymock.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.easymock.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
    at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:175)
    at org.easymock.internal.MocksControl.createMock(MocksControl.java:113)
    at org.easymock.internal.MocksControl.createMock(MocksControl.java:94)
    at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:1998)
    at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:1945)
    at org.powermock.api.easymock.PowerMock.createMock(PowerMock.java:85)
    at com.ibm.cio.ecm.common.jsonschema.test.JsonSchemaValidatorTest.testJsonSchemaValidatorFailures(JsonSchemaValidatorTest.java:122)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    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)

I checked PowerMock.doMock() and it looks to me like it can only be used to mock final classes in the java.* namespace.  Here is the excerpt from org.powermock.api.easymock.PowerMock:

        IMocksControl control = mockStrategy.createMockControl(type);
        MockRepository.addAfterMethodRunner(new EasyMockStateCleaner());
        T mock;
        if (type.isInterface()) {
            mock = control.createMock(type);
        } else if (type.getName().startsWith("java.") && Modifier.isFinal(type.getModifiers())) {
            Class<?> replicaType = createReplicaType(type, isStatic, constructorArgs);
            final Object replica = doCreateMock(replicaType, constructorArgs, control, methods);
            control = mockStrategy.createMockControl(replicaType);
            MockInvocationHandler h = new MockInvocationHandler((MocksControl) control);

Am I missing something here?  Can I not use PowerMock to mock any final class?

Thanks,
Scott

Arthur Zagretdinov

unread,
Mar 17, 2016, 3:06:26 AM3/17/16
to powe...@googlegroups.com
Hello, 

Looks like the “com.github.fge.jsonschema.main.JsonSchemaFactory” was prepared for test, so you need add the class to @PrepareForTest annotation. 

PowerMock can mock any final class, not only system, Java Classes. PowerMock uses byte code modification to remove “final” modifier by using custom class loader. But java system classes are always loaded with bootstrap class loader and PowerMock has no way to modify java system classes and we use workaround to mock java classes. what’s why you see this if statement in code. You can find more information about how PowerMock works here



Best regrads,
Arthur Zagretdinov
arthur.za...@outlook.com
Mobile phone/Whatsapp/Telegram: +7 (963) 120 65 67

--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To unsubscribe from this group and stop receiving emails from it, send an email to powermock+...@googlegroups.com.
To post to this group, send email to powe...@googlegroups.com.
Visit this group at https://groups.google.com/group/powermock.
For more options, visit https://groups.google.com/d/optout.

signature.asc
Reply all
Reply to author
Forward
0 new messages