#42 Class mocking not working for Eclipse plugin-in test

EasyMock_3.0
open
nobody
EasyMock (40)
5
2014-08-25
2010-09-27
Petar Zhechev
No

When using class mocking in a simple Eclipse JUnit plug-in test, and error occurs.
In plugins folder I have added additional bundles:

easymock-3.0.jar
com.springsource.net.sf.cglib_2.2.0.jar
org.objenesis_1.2.0.jar

Two sample projects which can be used to reproduce the problem are attached, simply import them in Eclipse and run EasyMockClassMocking/test.EasyMockTest from Run-as->JUnit plug-in test . Also I used 3 additional bundles, in my Eclipse plugins folder I have added:

http://ondex.rothamsted.bbsrc.ac.uk/nexus/content/groups/public/net/sourceforge/cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar
http://easymock.org/maven/repository/org/objenesis/objenesis/1.2/objenesis-1.2.jar
http://easymock.org/maven/repository/org/easymock/easymock/3.0/easymock-3.0.jar

Error that is triggered by EasyMock:

net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
at org.easymock.internal.ClassProxyFactory.createProxy(ClassProxyFactory.java:190)
at org.easymock.internal.MocksControl.createMock(MocksControl.java:60)
at org.easymock.EasyMock.createMock(EasyMock.java:104)
at test.EasyMockTest.testClassMocking(EasyMockTest.java:15)
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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
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.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62)
at org.eclipse.pde.internal.junit.runtime.CoreTestApplication.run(CoreTestApplication.java:23)
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.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:587)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:198)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:369)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
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.eclipse.equinox.launcher.Main.invokeFramework(Main.java:619)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:574)
at org.eclipse.equinox.launcher.Main.run(Main.java:1407)
at org.eclipse.equinox.launcher.Main.main(Main.java:1383)
Caused by: java.lang.reflect.InvocationTargetException
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 net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
... 47 more
Caused by: java.lang.NoClassDefFoundError: test/ProductiveClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
... 53 more
Caused by: java.lang.ClassNotFoundException: test.ProductiveClass
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:506)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 56 more

Cheers,
Petar

Discussion

  • Petar Zhechev
    Petar Zhechev
    2010-09-27

    Sample projects to reproduce bug

     
    Attachments
  • Petar Zhechev
    Petar Zhechev
    2010-09-27

    I would like to propose short how this can be fixed.
    In org.easymock.internal.ClassProxyFactory lines 180 - 192:

        Class mockClass;
        try {
            mockClass = enhancer.createClass();
        } catch (final CodeGenerationException e) {
            // ///CLOVER:OFF (don't know how to test it automatically)
            // Probably caused by a NoClassDefFoundError, let's try EasyMock class loader
            // instead of the default one (which is the class to mock one
            // This is required by Eclipse Plug-ins, the mock class loader doesn't see
            // cglib most of the time. Using EasyMock class loader solves this
            // See issue ID: 2994002
            mockClass = enhancer.createClass();
            // ///CLOVER:ON
        }
    

    So here you first try to load with the mock class loader, which doesent know about cglib. Then you try to load with easymock bundle class loader which knows cglib, but unfortunately doesn't know about the mock. So a combinantion of the 2 loaders (the one from the mock and the one from easymock bundle) should do. Here is my proposal for fix (it uses a classloader from jmock, the same one is used in mockito):

    import org.jmock.internal.SearchingClassLoader;
    ...
    Class mockClass;
    try {
    mockClass = enhancer.createClass();
    } catch (final CodeGenerationException e) {
    // ///CLOVER:OFF (don't know how to test it automatically)
    // Probably caused by a NoClassDefFoundError, let's try EasyMock class loader
    // instead of the default one (which is the class to mock one
    // This is required by Eclipse Plug-ins, the mock class loader doesn't see
    // cglib most of the time. Using EasyMock class loader solves this
    // See issue ID: 2994002
    SearchingClassLoader combinedLoader = new SearchingClassLoader(toMock.getClassLoader(), ClassProxyFactory.class.getClassLoader());
    enhancer.setClassLoader(combinedLoader);
    mockClass = enhancer.createClass();
    // ///CLOVER:ON
    }

    When this is applied, class mocking works just fine for Eclipse plug-in tests.
    What do you think?

     
  • David Erickson
    David Erickson
    2011-05-25

    I have the same problem using Mocks in an OSGi environment when proxying classes. This patch worked fine for me, and it would be great if we can get this mainlined (even if a custom Classloader has to be written it is super simple), as it is blocking anyone doing OSGi + Class mocking.

    -David

     
  • Jacob Godserv
    Jacob Godserv
    2014-04-01

    Is there a status update for this bug? I am also affected (3.2) but it appears this bug is abandoned.

     
    Last edit: Jacob Godserv 2014-04-01