【问题标题】:Can't use PowerMock with Robolectric不能将 PowerMock 与 Robolectric 一起使用
【发布时间】:2012-06-01 08:09:05
【问题描述】:

正如在此链接中所讨论的 - https://groups.google.com/group/powermock/browse_thread/thread/25ba2b85d9e576f4,我尝试使用 PowerMock 和 Robolectric 来模拟静态方法。但它抛出了一些难以理解的异常。

下面是我的测试类:

package net.therap.passreset.service;

import android.content.Context;
import com.xtremelabs.robolectric.Robolectric;
import net.therap.passreset.util.ConnectivityStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import roboguice.RoboGuice;
import roboguice.activity.RoboActivity;
import roboguice.test.RobolectricRoboTestRunner;

import static org.easymock.EasyMock.expect;
import static org.powermock.api.easymock.PowerMock.mockStatic;

/**
 * @author sharafat
 */
@RunWith(RobolectricRoboTestRunner.class)
@PrepareForTest(ConnectivityStatus.class)
public class TherapWebServiceClientTest {
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    private Context context = new RoboActivity();
    private TherapWebServiceClient therapWebServiceClient;

    @Before
    public void setUp() throws Exception {
        RoboGuice.setBaseApplicationInjector(Robolectric.application, RoboGuice.DEFAULT_STAGE);
        therapWebServiceClient = RoboGuice.getInjector(context).getInstance(TherapWebServiceClient.class);
        mockStatic(ConnectivityStatus.class);
    }

    @After
    public void tearDown() throws Exception {
        RoboGuice.util.reset();
    }

    @Test
    public void testLogin_success() {
        Robolectric.setDefaultHttpResponse(200, "");
        expect(ConnectivityStatus.isInternetConnected(context)).andReturn(true);

        therapWebServiceClient.login("", "", "");
    }
}

运行测试会产生以下异常:

com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field roboguice.activity.RoboActivity.__shadow__
---- Debugging information ----
field               : __shadow__
class               : roboguice.activity.RoboActivity
required-type       : roboguice.activity.RoboActivity
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/fNext/fNext/fTarget/context/__shadow__
line number         : 16
class[1]            : net.therap.passreset.service.TherapWebServiceClientTest
class[2]            : org.junit.internal.runners.statements.InvokeMethod
class[3]            : org.junit.internal.runners.statements.RunBefores
class[4]            : org.junit.internal.runners.statements.RunAfters
class[5]            : org.powermock.modules.junit4.rule.PowerMockStatement
class[6]            : org.powermock.modules.junit4.rule.PowerMockStatement$1
version             : null
-------------------------------
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.determineType(AbstractReflectionConverter.java:453)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:294)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1052)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1036)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:912)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:903)
    at org.powermock.classloading.DeepCloner.clone(DeepCloner.java:54)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:89)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78)
    at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49)
    at com.xtremelabs.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:292)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)


Process finished with exit code 255

如果我从类中删除 context 字段并将其替换为代码中其他地方的 new RoboActivity(),则会引发以下异常:

java.lang.NullPointerException
    at roboguice.RoboGuice.setBaseApplicationInjector(RoboGuice.java:116)
    at net.therap.passreset.service.TherapWebServiceClientTest.setUp(TherapWebServiceClientTest.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
    at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:2014)
    at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:885)
    at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:713)
    at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:98)
    at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78)
    at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49)
    at com.xtremelabs.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:292)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:24)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)


Process finished with exit code 255

上述异常似乎表明 Robolectric 无法创建应用程序上下文。关于如何使两者协同工作的任何想法?

【问题讨论】:

    标签: android powermock robolectric


    【解决方案1】:

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

    除了标准的 PowerMock jar,还需要 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());
        }
    }
    

    【讨论】:

    • 此设置将允许 mockStatic 和其他 Powermock 功能,但您将无法模拟 Android 系统类,因为它们已被 Robolectric 的 org.robolectric.* 类取代。跨度>
    • @PLNech 是的,但是在 Robolectric 环境中,您不想模拟 Android 类,Robolectric 会为您做到这一点。 :) 您仍然可以使用自定义 Robolectric 阴影类。
    • 好点,但我一直无法使用 Robolectric + PowerMock 模拟 android 系统类(例如创建模拟 java.net.URL)。你有这种用法的例子吗?
    • 正如我所说,你不必模拟类,你可以使用shadow classes
    • 你应该为此打开一个新问题。
    【解决方案2】:

    将您的 PowerMock 更新到 1.4.9 以上版本。我想我使用的是 1.5.1,但没有看到同样的错误。我有:

    @RunWith(RobolectricTestRunner.class)
    @PrepareForTest(MyStaticClass.class)
    

    它们不冲突。

    见:https://github.com/jayway/powermock/wiki/PowerMockAgent

    【讨论】:

    • 非常感谢。有时间我会试一试的。并感谢您提供宝贵的链接... :)
    • 没问题!如果它有助于/解决问题,请不要忘记投票并接受答案! :D
    猜你喜欢
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 2013-12-31
    • 2016-09-25
    • 1970-01-01
    • 2016-07-09
    • 2016-04-14
    • 1970-01-01
    相关资源
    最近更新 更多