I’m trying to write a unit test for my android app but having trouble doing what I want with mockito. This is being used in conjunction with Robolectric which I have working just fine and have demonstrated that unit tests work.
I want to test whether or not a button will open a new activity depending on whether there is some bluetooth device connected. Obviously, there is no device connected with bluetooth in my test, however I want to pretend as though there is. The state of the bluetooth connection is stored in my Application class. There is no publicly accessible method to change this value.
So basically the logic in the app is like this:
HomeActivity.java:
//this gets called when the button to open the list is clicked.
public void openListActivity(View button) {
MyApplication myApplication = (MyApplication) getApplication();
if (myApplication.isDeviceConnected() {
startActivity(new intent(this, ListActivity.class));
}
}
So to test this I did the following:
TestHomeActivity.java:
@Test
public void buttonShouldOpenListIfConnected() {
FlexApplication mockedApp = Mockito.mock(MyApplication.class);
Mockito.when(mockedApp.isDeviceConnected()).thenReturn(true);
//listViewButton was setup in @Before
listViewButton.performClick();
ShadowActivity shadowActivity = Robolectric.shadowOf(activity);
Intent intent = shadowActivity.getNextStartedActivity();
assertNotNull(intent); //this fails because no new activity was opened. I debugged this and found that isDeviceConnected returned false.
ShadowIntent shadowIntent = Robolectric.shadowOf(intent);
assertThat(shadowIntent.getComponent().getClassName(), equalTo(ListActivity.class.getName()));
}
So my unit test fails because the call (in the activity) to isDeviceConnected returns false even though I thought I told it to return true with the mock framework. I want my test to have this method return true though. Isn’t this what mockito does or am I totally mistaken on how to use mockito?
That’s how mockito works, but the problem is: is your
listViewButtonusing yourmockedApp? Seems not, because you’re creatingmockedAppat the test method and never setting it anywhere. Mockito will not mock the method calls of all instances ofApplication, only from what you declared as a mock.I personally don’t know how android works with the
Applicationclass, but you will have to set it somewhere so listView use yourmockedAppinstead of what it receives normally.EDIT
After the updated question, you can transform your
getApplicationin a protected method,spyyoulistViewButtonand make it return yourmockedApp. That smells a little bad, but it’s one way if you can not set your application mocked object tolistViewButton.EDIT2
Example of using spy in your test using
BDDMockitofor readability 🙂After that, your test should work as expected. But I reinforce: Use
spyonly if you can’t inject yourmockedAppinside HomeActivity.