8
votes

I am trying to have RunWith(PowerMockRunner.class) working with my existing package annotation.

Versions:

powermock 1.4.12 mockito 1.9.0 junit 4.8.2

package-info.java // this is for the package annotation

@TestAnnotation(version="1.0")
package com.smin.dummy;

TestAnnotation.java // this is the the metadata annotation class for package "com.smin.dummy"

package com.smin.dummy;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface TestAnnotation {
  String version();
}

A.java

package com.smin.dummy;

public class A {
    private static Package myPackage;
    private static TestAnnotation version;

    static {
      myPackage = TestAnnotation.class.getPackage();
      version = myPackage.getAnnotation(TestAnnotation.class);
     }

    public static String getVersion() {
        return version.version();
    }
}

MockA.java

package com.smin.dummy;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.smin.dummy.A;

@RunWith(PowerMockRunner.class) //comment out this line to see the difference
@PrepareForTest(A.class)
public class MockA {
@Test
public void test_mocked() throws Throwable {
    String thisVersion = A.getVersion();
    System.out.println(thisVersion);
}
}

In the unitest MockA.java, if I don't use RunWith(PowerMockRunner.class), I will get the thisVersion printed 0.1 as expected. But after adding RunWith(PowerMockRunner.class), thisVersion turns into null. I suspect PowerMockRunner is doing some funny thing with the package annotation here, anybody has any idea? see the mini version of my code below:

1
I inspected the class loader of the junit test, when annotated with @RunWith(PowerMockRunner.class). It appears Powermock is setting its own class loader, and this is how the magic of injecting the mocked class into the test case happens. I'm affraid you're right, the package of the class generated by powermock is no longer annotated as it should be.Alban
@Alban good finding! any work around?Shengjie
I'm affraid not. Looking deeper at your problem, I inspected A.class, and found out that the annotation you set on the packageis actually replaced by a proxy. So getAnnotation(TestAnnotation.class)` returns null. If you loop over the list of annotations on the package, there is no annotation that is an instance or a super class instance of TestAnnotation.class. The annotation that actually is on the package is a proxy. I failed to find a way to instruct MockClassLoader to defer to the system class loader the loading of any class other than A. According to the java doc, it's possible.Alban

1 Answers

4
votes

Building on @Alban's sleuthing in the comments, it looks like adding this annotation to your test case should circumvent the problem:

@PowerMockIgnore("com.smin.dummy.TestAnnotation")