I have a method to test, that begins following:
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
contextString = adapter.getItem(info.position);
/.../
}
I would like to test it using Mockito, but if I declare menuInfo like this:
@Mock ContextMenuInfo menuInfo
then I cannot compile the following statement:
Mockito.when(menuInfo.position).thenReturn(1);
since it is not valid for ContextMenuInfo
object. I cannot declare my object as AdapterView.AdapterContextMenuInfo
class, since then I get an error during run time.
I know that in Mockito it is possible that a mock implements multiple interfaces, but the same does not apply to classes. How would it be possible to test the method I shown above?
Mockito works by using Java inheritance to replace the implementations of methods on a class. However, it looks like position
is a field on AdapterContextMenuInfo
, which means that Mockito can't mock it for you.
Luckily, AdapterContextMenuInfo has a public constructor, so you don't have to mock it—you can just create one for the test and pass it into your method.
@Test public void contextMenuShouldWork() {
ContextMenuInfo info =
new AdapterView.AdapterContextMenuInfo(view, position, id);
systemUnderTest.onCreateContextMenu(menu, view, info);
/* assert success here */
}
If you're ever stuck in this pattern for a class that you can't directly mock or instantiate, consider creating a helper class that you can mock:
class MyHelper {
/** Used for testing. */
int getPositionFromContextMenuInfo(ContextMenuInfo info) {
return ((AdapterContextMenuInfo) info).position;
}
}
Now you can refactor your View to use that:
public class MyActivity extends Activity {
/** visible for testing */
MyHelper helper = new MyHelper();
public void onCreateContextMenu(
ContextMenu menu, View v, ContextMenuInfo menuInfo) {
int position = helper.getPositionFromContextMenuInfo(menuInfo);
// ...
}
}
...and then mock the helper in your test.
/** This is only a good idea in a world where you can't instantiate the type. */
@Test public void contextMenuShouldWork() {
ContextMenuInfo info = getSomeInfoObjectYouCantChange();
MyHelper mockHelper = Mockito.mock(MyHelper.class);
when(mockHelper.getPositionFromContextMenu(info)).thenReturn(42);
systemUnderTest.helper = mockHelper;
systemUnderTest.onCreateContextMenu(menu, view, info);
/* assert success here */
}
There is one other option, involving a refactor:
public class MyActivity extends Activity {
public void onCreateContextMenu(
ContextMenu menu, View v, ContextMenuInfo menuInfo) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) menuInfo;
onCreateContextMenuImpl(info.position);
}
/** visible for testing */
void onCreateContextMenuImpl(int position) {
// the bulk of the code goes here
}
}
@Test public void contextMenuShouldWork() {
systemUnderTest.onCreateContextMenuImpl(position);
/* assert success here */
}
May be use mockito's extraInterfaces
option
@Mock(extraInterfaces=AdapterView.AdapterContextMenuInfo.class)
ContextMenuInfo menuInfo
and then mock it like
Mockito.doReturn(1).when((AdapterView.AdapterContextMenuInfo)menuInfo).position
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With