I am writing Unit Tests for an app module. I somehow have problems with mocking Android calls. What I don't want is to use an InstrumentationTest for my test case.
Here are my classes. Beginning with a less important model class:
package de.mk_xappo.mockitoexample;
import java.io.Serializable;
public class SpecialData implements Serializable {
int someData_1;
int someData_2;
public int getSomeData_1() {
return someData_1;
}
public void setSomeData_1(int someData_1) {
this.someData_1 = someData_1;
}
public int getSomeData_2() {
return someData_2;
}
public void setSomeData_2(int someData_2) {
this.someData_2 = someData_2;
}
}
Here is my centralized manager for launching Activities:
package de.mk_xappo.mockitoexample;
import android.content.Context;
import android.content.Intent;
public class IntentManager {
private Context context;
public IntentManager(Context context) {
this.context = context;
}
public boolean goToSpecialActivity(SpecialData specialData) {
Intent intent = new Intent(context, SpecialActivity.class);
intent.putExtra(SpecialActivityManager.INTENT_EXTRA_SPECIAL_DATA, specialData);
context.startActivity(intent);
return true;
}
}
Here is my "specialized" manager:
package de.mk_xappo.mockitoexample;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
public class SpecialActivityManager {
private final SharedPreferences sharedPreferences;
private final IntentManager intentManager;
private boolean specialShouldBeShown = true;
public static final String INTENT_EXTRA_SPECIAL_DATA = "INTENT_EXTRA_SPECIAL_DATA";
public SpecialActivityManager(Context context) {
sharedPreferences = context.getSharedPreferences(context.getPackageName() + ".special", Activity.MODE_PRIVATE);
this.intentManager = new IntentManager(context);
}
public void showSpecial(SpecialData specialData) {
if (specialShouldBeShown) {
intentManager.goToSpecialActivity(specialData);
}
}
}
And here is my unit test:
package de.mk_xappo.mockitoexample;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class SpecialManagerTest {
private Context context;
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;
private SpecialActivityManager specialActivityManager;
private Intent intent;
@Before
public void setUp() throws Exception {
context = mock(Context.class);
intent = mock(Intent.class);
sharedPreferences = mock(SharedPreferences.class);
editor = mock(SharedPreferences.Editor.class);
when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences);
when(sharedPreferences.edit()).thenReturn(editor);
when(editor.putBoolean(anyString(), anyBoolean())).thenReturn(editor);
specialActivityManager = new SpecialActivityManager(context);
}
@Test
public void testShowSpeciall() throws Exception {
SpecialData specialData = mock(SpecialData.class);
IntentManager intentManager = mock(IntentManager.class);
when(intentManager.goToSpecialActivity(specialData)).thenReturn(true);
specialActivityManager.showSpecial(specialData);
verify(intent).putExtra(SpecialActivityManager.INTENT_EXTRA_SPECIAL_DATA, specialData);
verify(context).startActivity(intent);
}
}
Now I get the following exception:
java.lang.RuntimeException: Method putExtra in android.content.Intent not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.content.Intent.putExtra(Intent.java)
at de.mk_xappo.mockitoexample.IntentManager.goToSpecialActivity(IntentManager.java:18)
at de.mk_xappo.mockitoexample.SpecialActivityManager.showSpecial(SpecialActivityManager.java:23)
at de.mk_xappo.mockitoexample.SpecialManagerTest.testShowSpeciall(SpecialManagerTest.java:46)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
I already tried to follow this link. But then I could not verify my method calls:
verify(intent).putExtra(SpecialActivityManager.INTENT_EXTRA_SPECIAL_DATA, specialData);
verify(context).startActivity(intent);
So is it possible to somehow mock the putExtra()
method or do you have any other solution for me?
In your
SpecialManagerTest
you just need to test thatintentManager.goToSpecialActivity(specialData)
is called.If the new activity is started is a responsibility of
IntentManager
and it should be tested there.First to make
SpecialManager
testable you need to pass its attributes as parameters (in that way you can mock them):Then your test should be: