使用PowerMock和Robolectric-IncompatibleClassChangeError - java

我正在尝试使用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
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
在java.lang.reflect.Method.invoke(Method.java:597)
在sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:323)
在sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:348)

原因:java.lang.IncompatibleClassChangeError:实现类
在java.lang.ClassLoader.defineClass1(本机方法)
在java.lang.ClassLoader.defineClassCond(ClassLoader.java:637)
在java.lang.ClassLoader.defineClass(ClassLoader.java:621)
在java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)

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

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

在每个单元测试中。

根据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());
    }
}

参考方案

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

除了标准的PowerMock罐子之外,还需要PowerMock Junit Rule。描述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());
    }
}

通过Maven编译器插件不会发生有限的包含和排除 - java

我正在使用3.6.0版的maven编译器插件,在此我们只想在特定文件夹中编译一个文件,而在该位置编译所有其他文件。例如:在文件夹应用程序中有14个文件,从那我只希望编译1个文件,但它编译了所有文件,如果我要排除,则它也不起作用。 <sourceDirectory>${basedir}/../src/java</sourceDirectory…

休眠映射<键,设置<值>> - java

我有以下表格:@Entity @Table(name = "events") Event --id --name @Entity @Table(name = "state") State --id --name @Entity @Table(name = "action") Action --id …

与哪些运算符>>兼容 - java

我这里没有什么代码int b=3; b=b >> 1; System.out.println(b); 它可以完美工作,但是当我将变量b更改为byte,short,float,double时,它包含错误,但是对于变量int和long来说,它可以完美工作,为什么它不能与其他变量一起工作? 参考方案 位移位运算符(例如>>)与任何整数类型兼…

在集成测试阶段执行Maven模块 - java

我想启动一个同级Maven 3模块,该模块在我的一个Maven模块中充当应用程序服务器,以对系统运行集成测试。我的maven项目看起来与此类似:父模块模块A模块B现在,我想在Maven的集成前测试阶段中启动“模块A”,然后运行模块B中包含的所有集成测试。我设法在模块B中运行了集成测试,但是没有找到“光滑”的方法在集成前测试阶段启动模块B。最佳做法是什么?使用…

当我所有的都是T时,如何返回Interface <T>的实例? - java

我有一个界面:public interface ILoginResult<T> { public T get(); } 我有一个LoginPage对象:public class LoginPage<T> { ... public ILoginResult<T> login(...) { ... } } 我也有一些登录页面对…