Android 单元测试中的 ArraySet 未被模拟

Android ArraySet in unit tests is not mocked

在代码中使用 android.util.ArraySet 时,我无法在我的非 android 测试 类 中使用它来测试 类,因为它会抛出异常:

java.lang.RuntimeException: Method add in android.util.ArraySet not mocked. See http://g.co/androidstudio/not-mocked for details.

link 说:

This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito)

如何使用 ArraySet 对代码进行单元测试?我会说以某种方式嘲笑(Mockito,PowerMock)它 "replacing it with a HashSet" 可能是有前途的:

待测代码:

Set<Bird> birds = new ArraySet<>();
birds.add(currentBird);

测试代码:

whenNew(ArraySet.class).withAnyArguments().thenAnswer(new Answer<Object>() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return new HashSet();
    }
});

这给出 java.lang.ClassCastException: java.util.HashSet cannot be cast to android.util.ArraySet.

解决方法是不 return 一个 HashSet,而是一些 MyFakeArraySet extends ArraySet(内部使用 HashSet),但遗憾的是 ArraySet final。 :-(

你不应该在你的非android测试中使用android sdk 类 类.

但如果你愿意,你可以使用这样的东西:

    @Test
public void testArraySet() {
    final Set<Bird> fakeBirds = new HashSet<>();
    ArraySet<Bird> birds = (ArraySet<Bird>) Mockito.mock(ArraySet.class);

    when(birds.add(any(Bird.class))).then(new Answer<Boolean>() {
        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            Bird param = invocation.getArgument(0);
            return fakeBirds.add(param);
        }
    });

    when(birds.contains(any(Bird.class))).then(new Answer<Boolean>() {
        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            Bird param = invocation.getArgument(0);
            return fakeBirds.contains(param);
        }
    });

    Bird bird = new Bird();
    birds.add(bird);

    assert birds.contains(bird);
}

我发现测试文件夹中的 classes 似乎具有优先权。所以我不需要模拟任何东西。我可以将一个包 android.util 放入我的测试文件夹和一个 ArraySet class 完全由我指定:

package android.util;

import android.support.annotation.NonNull;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;


public class ArraySet<E extends Object> implements Collection<E>, Set<E> {
    private final HashSet<E> HASH_SET;

    public ArraySet(int capacity) {
        Log.e("ArraySet", "WARNING, using fake array set!");
        HASH_SET = new HashSet<>(capacity);
    }

    @Override
    public int size() {
        return HASH_SET.size();
    }

    // Do this with all other methods as well: Chain them into HASH_SET.
}