Search code examples
androidunit-testingmockitopowermockpowermockito

Android ArraySet in unit tests is not mocked


When using android.util.ArraySet in code, I cannot test the classes using it in my non-android test classes, because it would throw an exception:

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

The link says:

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)

How can I unit test code using ArraySet? I would say somehow mocking (Mockito, PowerMock) it by somehow "replacing it with a HashSet" could be promising:

Code to be tested:

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

Test code:

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

This gives java.lang.ClassCastException: java.util.HashSet cannot be cast to android.util.ArraySet.

A workaround would be to not to return a HashSet but some MyFakeArraySet extends ArraySet (which internally uses a HashSet), but sadly ArraySet is final. :-(


Solution

  • I've found out that the classes in the test folders seem to have precedence. So I do not have to mock anything. I can just place a package android.util into my test folders and an ArraySet class completely specified by me:

    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.
    }