Powermock和Robolectric:android应用程序类和私有方法模拟的问题

时间:2017-06-29 12:32:12

标签: android mocking powermock robolectric powermockito

我正在复杂的Android应用程序中进行测试,我正在尝试让Robolectric和Powermock一起工作。我有奇怪的行为,所以我试图分解问题以隔离它。 我介绍了powermock来模拟一些静态和私有方法,但是当我打电话给我时,我注意到了

PowerMockito.doReturn(valueToReturn).when(classUnderTest, "myPrivateMethod", anyString(), anyInt());

myPrivateMethod中的代码实际上已执行。此外,我还使用Robolectric和自定义Application类,并且在测试执行期间在自定义应用程序类中声明的变量为null,即使我仔细检查它们是否已正确初始化。

我做的第一次尝试就是写一个非常简单的类并测试它而不涉及其他任何事情。

班级就是这个

public class MyClient {

    public boolean publicApi() {
        System.out.println("In publicApi");
        System.out.println("Application.self = " + BaseApplication.self());
        int result = 0;
        try {
            result = privateApi("hello", 1);
        } catch (Exception e) {
            Assert.fail();
        }
        System.out.println("result : " + result);
        return result == 20;
    }

    private int privateApi(String whatever, int num) throws Exception {
        System.out.println("In privateAPI");
        thirdPartyCall();
        int resp = 10;
        return resp;
    }

    private void thirdPartyCall() throws Exception {
        System.out.println("In thirdPartyCall");
        //Actual WS call which may be down while running the test cases
    }
}

这是测试

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClient.class)
public class MyClientTest1 {

    @Test
    public void testPublicAPI() throws Exception {
        MyClient classUnderTest = PowerMockito.spy(new MyClient());

        PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());

        boolean result = classUnderTest.publicApi();
        Assert.assertTrue(result);
    }
}

在这种情况下,我有预期的结果,输出是

In publicApi
Application.self = null
result : 20

然后我尝试引入robolectric。应用程序类就是这个

public class MyTestApplication
    extends BaseApplication {

    @Override
    public void onCreate() {
        super.onCreate();
    }

}

BaseApplication就是这个

/**
 * Real application class
 */
public class BaseApplication
    extends Application {
    protected static BaseApplication sSelf;

    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("filling Application.self");
        sSelf = this;
    }

    public static BaseApplication self() {
        return sSelf;
    }
}

这是测试

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@Config(manifest = Config.NONE, application = MyTestApplication.class)
@PrepareForTest(MyClient.class)
public class MyClientTest2 {

    @Test
    public void testPublicAPI() throws Exception {
        MyClient classUnderTest = PowerMockito.spy(new MyClient());

        PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());

        boolean result = classUnderTest.publicApi();

        Assert.assertTrue(result);
    }
}

输出

filling Application.self
In privateAPI
In thirdPartyCall

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 2 recorded:
-> at com.myapp.MyClientTest2.testPublicAPI(MyClientTest2.java:31)
-> at com.myapp.MyClientTest2.testPublicAPI(MyClientTest2.java:31)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

正如你在这里看到的第一个陌生感:当我调用

时执行私有方法
PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());

并且同一个调用(第31行就是那个)抛出异常

然后我再次尝试使用PowerMockRule将Robolectric和Powermock以其他建议的方式集成到文档中

@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@Config(manifest = Config.NONE, application = MyTestApplication.class)
@PrepareForTest(MyClient.class)
public class MyClientTest3 {

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Test
    public void testPublicAPI() throws Exception {
        MyClient classUnderTest = PowerMockito.spy(new MyClient());

        PowerMockito.doReturn(20).when(classUnderTest, "privateApi", anyString(), anyInt());

        boolean result = classUnderTest.publicApi();

        Assert.assertTrue(result);
    }
}

这是输出:

filling Application.self
In publicApi
Application.self = null
result : 20

此处异常消失,私有方法被成功模拟,但另一个问题出现:MyTestApplication.self()在访问时返回null,即使日志filling Application.self表示sSelf变量是valorized(我也在调试器中检查过它)

这最后一个解决方案似乎是最好的解决方案,但它导致的问题使我无法使用它,因为我使用Application.self()来访问许多与dagger相关的东西。

此时sSelf字段如何为空?

非常感谢您的帮助

0 个答案:

没有答案