使用时的Mockito Android的方法不是嘲笑不是、方法、Mockito、Android

由网友(94号少年)分享简介:我正在写一个测试,目的是测试在适配器类(按 RecyclerView )。嘲笑适配器的行为我选择了图书馆的Mockito。 I'm writing a test which purpose is to test some methods in subclass of Adapter class (used by Re...

我正在写一个测试,目的是测试在适配器类(按 RecyclerView )。嘲笑适配器的行为我选择了图书馆的Mockito。

I'm writing a test which purpose is to test some methods in subclass of Adapter class (used by RecyclerView). To mock adapter behavior I've chosen Mockito library.

下面是一个简单的测试:

Here's a simple test:

import android.support.v7.widget.RecyclerView.Adapter;

public class TestAdapter {

    @Test
    public void testAdapter() throws Exception {
        Adapter adapter = Mockito.mock(Adapter.class);

        adapter.notifyDataSetChanged();
    }
}

没有什么应该发生,但 NullPointerException异常代替抛出。

java.lang.NullPointerException
    at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:5380)
    at pl.toro.test.adapter.TestAdapter.testAdapter(TestAdapter.java:38)
    ...

我也试过用间谍而不是模拟

@Test
public void testAdapterWithDoNothing() throws Exception {
    Adapter adapter = Mockito.spy(new Adapter() {...});
    doNothing().when(adapter).notifyDataSetChanged();
}

但这种失败在第二行(注意这只是一个模拟设置)

But this fails at second line (notice this is just a mock setup)

java.lang.NullPointerException
    at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:8946)
    at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:5380)
    at pl.toro.test.adapter.TestAdapter.testAdapterWithDoNothing(TestAdapter.java:59)
    ...

是否有可能与嘲弄支持的Mockito类的单元测试?

Is it possible to mock support classes with Mockito in unit tests?

推荐答案

Android的支持类服从的同样对什么可以或不可以被嘲笑规则的Java 的休息;不幸的是,你指的是方法( notifyDataSetChanged )是最终决定。您也可以考虑这个的嘲笑你没有自己类型的危害的,因为最后语义影响类是否可以嘲笑。

Android support classes obey the same rules as the rest of Java regarding what can or can't be mocked; unfortunately, the method you're referring to (notifyDataSetChanged) is final. You may also consider this a hazard of mocking types you don't own, as the final semantics affect whether the class can be mocked.

在内部,工作的Mockito通过创建你嘲讽之类的子类(实际上是一个代理服务器实现)。因为最后方法解析可以在编译时有发生,爪哇跳过多态性方法查找并直接调用你的方法。这在稍快生产的,但没有方法查找丢失的Mockito重定向呼叫的唯一方式。

Internally, Mockito works by creating a "subclass" (actually a proxy implementation) of the class you're mocking. Because final method resolution can happen at compile time, Java skips the polymorphic method lookup and directly invokes your method. This is slightly faster in production, but without the method lookup Mockito loses its only way to redirect your call.

这是在整个Android SDK和支持库屡见不鲜。你可以考虑以下解决方案之一:

This is a common occurrence across the Android SDK and support libraries. You might consider one of the following resolutions:

重构系统介绍自己控制的包装类,这是很简单的要求很少或没有测试。

Refactor your system to introduce a wrapper class that you control, which is simple enough to require little or no testing.

使用 Robolectric ,它采用了特殊的Andr​​oid的SDK-针对JVM的类加载器,可以改写成来电mockable当量(也是分析和测试Android版提供资源,而无需仿真器)。 Robolectric提供了足够的特定Android的阴影(替换实现),你通常可以避免编写自己的,但也允许像支持库的情况下定制的阴影。

Use Robolectric, which uses a special Android-SDK-targeted JVM classloader that can rewrite calls into mockable equivalents (and also parses and supplies Android resources for testing without an emulator). Robolectric provides enough Android-specific "shadows" (replacement implementations) that you can usually avoid writing your own, but also allows for custom shadows for cases like support libraries.

使用 PowerMock ,延伸或的Mockito EasyMock的使用一种特殊的类加载器还重写你的系统在测试时的字节code。不像Robolectric,它不是Android的针对性,使其成为一个更通用的解决方案,但通常需要更多的设置。

Use PowerMock, which extends Mockito or EasyMock using a special classloader that also rewrites the bytecode of your system under test. Unlike Robolectric, it is not Android-targeted, making it a more general-purpose solution but generally requiring more setup.

PowerMock是的的Mockito的延伸,所以它提供严格的更多的功能,但我个人尝试重构各地的任何问题都需要它。

PowerMock is an extension of Mockito, so it provides strictly more functionality, but personally I try to refactor around any problem that would require it.