indi mars
indi mars

Reputation: 133

robolectric 3.0 Mockito -- how to mock a class inside activity

I am in process of migration to robolectric 3.0

Problem Statement--

I have a class AppUtility, which is instantiated inside MyActivity, so to check its methods are invoked, I need to mock it inside my test before setting up the MyActivity.

Here is my code:

@Mock
private AppUtility mockAppUtility;

@Before
public void setUp() {
    initMocks(this);
    myActivity= Robolectric.setupActivity(MyActivity.class);
    equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
    shadowActivity = Shadows.shadowOf(myActivity);
}

Here is the test method:--

  @Test
        public void shouldCallStartAlarm() {
            for (int i = 0; i < 4; i++) {
                equalsButton.performClick();
            }
            verify(mockAppUtility).startAlarm();
        }

Bu I get the following error msg:-- which show mock is not linked to the activity, how can I bind it to activity??

Actually, there were zero interactions with this mock.

But the mock object is not associated with the test. With earlier version of Robolectric I use to associate the mock object on activity creation, by overriding it as below

 myActivity = new MyActivity() {
                @Override
                AppUtility getUtil() {
                    return mockAppUtility;
                }
            };
            myActivity.onCreate(new Bundle());

and it use to work fine, with Robolectric 3.0 , how can I bind the mock object before starting the activity.

Following @nenick your second option:This is how it looks

    @Mock
    private AppUtility appUtility;
    @InjectMocks
    private MyActivity myActivity;
    @Before
    public void setUp() {
        ActivityController<MyActivity> activityController = Robolectric.buildActivity(MyActivity.class);
//      myActivity= Robolectric.setupActivity(MyActivity.class);
        myActivity=activityController.get();
        initMocks(this);
        activityController.setup();
        equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
//      shadowActivity = Shadows.shadowOf(calculatorActivity);
    }

but I get fllowing exception:-

java.lang.IllegalArgumentException: attempted to invoke public final android.app.Application org.robolectric.shadows.ShadowActivity.getApplication() on instance of class org.com.android.AppUtility$$EnhancerByMockitoWithCGLIB$$77c74666, but AppUtility$$EnhancerByMockitoWithCGLIB$$77c74666 doesn't extend ShadowActivity

it breaks at step--activityController.setup();

Upvotes: 2

Views: 5085

Answers (2)

nenick
nenick

Reputation: 7438

Just set mock is easy with mockito mock injection feature.

@Mock
private AppUtility mockAppUtility;

@InjectMocks
Activity mActivity;

@Before
public void setUp() {
  myActivity= Robolectric.setupActivity(MyActivity.class);
  equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
  shadowActivity = Shadows.shadowOf(myActivity);

  // create and injects mocks into object annotated with @InjectMocks
  initMocks(this);
}

To set mocks before activity setup (onCreate, ...) is called you must access your activity before setup.

@Before
public void setUp() {
  ActivityController<Activity> activityController = Robolectric.buildActivity(Activity.class);

  // get the activity instance 
  mActivity = activityController.get()

  initMocks(this);

  // now setup your activity after mock injection
  activityController.setup()
}

Upvotes: 4

Eugen Martynov
Eugen Martynov

Reputation: 20130

One of the main rule of unit testing - never mock class under the test. You might spy on it but again it is rescue challenge which you should not use in this case.

Another smell showing that you have wake test - when you will be able to run this tests successfully it will not guarantee that real alarm set. It will guarantee only that this method was called. So it is better to verify set alrams instead of verifying method call. Check this link for the example use of shadow alarm manager

Upvotes: 0

Related Questions