2

recently I've been struggling with Mockito. But after valiant efforts, I made it compile without errors except this one in a particular case :

When I'm mocking a package-private class with Mockito, with a test in the same package, I get the following error :

java.lang.UnsupportedOperationException: cannot proxy inaccessible class class [...].AndroidCalendarGenerator.ManageEventsUI.CalendarMonitorServiceConnection
    at com.android.dx.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:269)
    at com.android.dx.mockito.DexmakerMockMaker.createMock(DexmakerMockMaker.java:56)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
    at org.mockito.Mockito.mock(Mockito.java:1285)
    at org.mockito.Mockito.mock(Mockito.java:1163)
    [...]

Here is my class :

package [...].AndroidCalendarGenerator.ManageEventsUI;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

import static org.mockito.Mockito.mock;

@RunWith(MockitoJUnitRunner.class)
public class CalendarMonitorServiceConnectionTest {

    @Test
    public void testOne() {
        CalendarMonitorServiceConnection c1 = new CalendarMonitorServiceConnection(null);
        CalendarMonitorServiceConnection c = mock(CalendarMonitorServiceConnection.class);
    }
}

I think that the first line of the test compiling without errors means that this test is in the same folder as the CalendarMonitorServiceConnection class that I try to mock.

Finally, I have those imports in my build.gradle :

androidTestCompile 'junit:junit:4.12'
androidTestCompile 'org.mockito:mockito-core:1.10.19'
androidTestCompile "com.crittercism.dexmaker:dexmaker:1.4"
androidTestCompile "com.crittercism.dexmaker:dexmaker-mockito:1.4"
androidTestCompile "com.crittercism.dexmaker:dexmaker-dx:1.4"

What am I missing ?

Thanks a lot for your answers


EDIT

Here's the code of the class I try to mock :

package [...].AndroidCalendarGenerator.ManageEventsUI;

import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import [...].AndroidCalendarGenerator.CalendarEventMonitor;
import [...].AndroidCalendarGenerator.Event;
import [...].AndroidCalendarGenerator.EventChangeListener;

class CalendarMonitorServiceConnection implements ServiceConnection {

    private CalendarEventMonitor mMonitor;
    private EventListViewAdapter mEventListViewAdapter;

    CalendarMonitorServiceConnection(EventListViewAdapter eventListViewAdapter) {
        mEventListViewAdapter = eventListViewAdapter;
    }

    /**
     * Custom event change listener that defines what to do in case of changes in the calendar
     */
    private class CustomEventChangeListener implements EventChangeListener {
        @Override
        public void onEventActivated(Event event) {
            //[...]
        }

        @Override
        public void onEventRemoved(Event event) {
            //[...]
        }

        @Override
        public void onEventListChanged() {
            //[...]
        }
    }

    /**
     * Pulls data for next 30 days and send it to the adapter
     */
    private void sendNextThirtyDaysEventsToAdapter() {
        //[...]
    }

    @Override
    public void onServiceConnected(ComponentName className,
                                   IBinder service){
        //[...]
    }

    @Override
    public void onServiceDisconnected(ComponentName arg0){
        //[...]
    }
}
Racater
  • 185
  • 3
  • 11
  • 1
    Please add the code of the class (and the enclosing class) you want to mock. – Timothy Truckle Nov 10 '16 at 18:24
  • Indeed, the code has been added :) – Racater Nov 10 '16 at 20:39
  • 2
    *'private class CustomEventChangeListener'* Mockito cannot mock something that's private or final. On the other hand, an inner (nonstatic!) class is an implementation detail which should not be mocked at all (information hiding). Either make the inner class a top level class of its own or find a different test approach. – Timothy Truckle Nov 10 '16 at 20:51
  • Thanks a lot ! Mockito cannot mock a non-private class containing a private class ? – Racater Nov 10 '16 at 21:30
  • 2
    *"Mockito cannot mock a non-private class containing a private class"* No. The *package private* top level class could be mocked if the test class is in the same packge. The problem is the contained `private class` (which is also not `static`) that cannot be mocked. – Timothy Truckle Nov 10 '16 at 22:14

1 Answers1

1

after some research, it seems to me that :

  • Mockito + Dexmaker cannot mock package-private class, even with the unit tests being in the same package.
  • Powermock can mock package-private class, but only if the unit tests are in the same package.

Therefore the solution, as I want to keep my class package-private, is to use Powermock.

Main sources :


I'll update the post as I try Powemock. Or if someone can agree or correct my answer.

Community
  • 1
  • 1
Racater
  • 185
  • 3
  • 11
  • Powermock is obsolete from most points of views now that Mockito is able to mock static things. So I doubt it is a wise decision to still invest into this. – arkascha Apr 25 '22 at 12:30