使用PowerMock和Robolectric - IncompatibleClassChangeError

时间:2013-12-13 01:52:58

标签: java android powermock robolectric

我正在尝试使用PowerMockito来模拟Android Robolectric测试中的一些静态方法。我正在使用JUnit 4.8.2,Robolectric 2.2,Mockito 1.9.5和PowerMock 1.9.5作为指示here。因为我必须使用RoboElectricTestRunner,所以我试图使用PowerMockRule来引导PowerMock。但是,当使用PowerMock进行测试时,我会遇到一个不幸的java.lang.IncompatibleClassChangeError

  

java.lang.reflect.InvocationTargetException
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)   在java.lang.reflect.Method.invoke(Method.java:597)
  at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)   at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:348)

     

引起:java.lang.IncompatibleClassChangeError:实现类   at java.lang.ClassLoader.defineClass1(Native Method)
  at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637)   at java.lang.ClassLoader.defineClass(ClassLoader.java:621)   在java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)

如果我将org.ow2.asm放在我得到的org.powermock库之后:

  

java.lang.IncompatibleClassChangeError:class org.objectweb.asm.tree.ClassNode具有接口org.objectweb.asm.ClassVisitor作为超类   at java.lang.ClassLoader.defineClass1(Native Method)   at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637)   at java.lang.ClassLoader.defineClass(ClassLoader.java:621)   at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)   at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)   at java.net.URLClassLoader.access $ 000(URLClassLoader.java:58)   在java.net.URLClassLoader $ 1.run(URLClassLoader.java:197)   at java.security.AccessController.doPrivileged(Native Method)

每次单元测试。

根据Maven依赖性:树Robolectric和PowerMock不共享任何依赖关系。 显然 org.powermock:powermock-module-javaagent 打包了一些 org / objectweb / asm 类,而Robolectric依赖于 org。 ow2.asm:asm:jar:4.1 导致冲突。


@RunWith(RobolectricTestRunner.class)
@PrepareForTest(Helper.class)
@PowerMockIgnore({"com.sun.jmx.*", "javax.management.*"})
public class HelpFragTest {

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    static {
        PowerMockAgent.initializeIfNeeded();
    }

    FragmentActivity fragmentActivity;
    FragmentManager fragmentManager;
    ActionBarManager actionBarManager;

    @Before
    public void setup(){
        actionBarManager = mock(ActionBarManager.class);
        LowesApplication.instance().setActionBarManager(actionBarManager);
        fragmentActivity = Robolectric.buildActivity(FragmentActivity.class).create().start().resume().get();
        fragmentManager = fragmentActivity.getSupportFragmentManager();
    }

    @Test
    public void testShow(){
        mockStatic(Helper.class);

        HelpFrag helpFrag = HelpFrag.newInstance();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        fragmentTransaction.add(helpFrag, null);
        fragmentTransaction.commit();

        assertTrue(helpFrag.isVisible());
    }
}

1 个答案:

答案 0 :(得分:9)

我找到了一种将PowerMock与Robolectric结合使用的方法。

除了标准的PowerMock jar之外,还需要PowerMock Junit规则。它被描述为here如何抓住它。我使用了xstream类加载版本,因为objenesis版本非常错误。这与PowerMock 1.5.5和Robolectric 2.3一起使用,我不能谈论旧版本。另请注意,不应包含Java代理,因为根据我的经验,它会导致问题。

因此,如果您使用maven,则应声明这些依赖项:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4-rule</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-classloading-xstream</artifactId>
    <version>${powermock.version}</version>
    <scope>test</scope>
</dependency>

然后你必须像这样设置你的测试类:

@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest(Static.class)
public class MyTest {

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    private MyActivity activity;

    @Before
    public void setup() {
        activity = Robolectric.buildActivity(MyActivity.class).create().get();
    }

    @Test
    public void test() throws Exception {
        PowerMockito.mockStatic(Static.class);
        Mockito.when(Static.getCurrentTime()).thenReturn(1);

        Assert.assertEquals(1, activity.getId());
    }
}