My task is to write Unit Test for existing Android activity and the code was not written to comply with unit testing (tight coupling).
Scenario: I have a class StroageManager, which is getting instantiated inside MyActivity onCreate method.
@Override
protected void onCreate(Bundle savedInstanceState)
{
StorageManager storagemanager = GetStorageManager(); // return new object of stroage manager
super.onCreate(savedInstanceState);.....
...
}
In order to create the instance of activity through Robolectric, I need to mock it inside my test before setting up the MyActivity.
Problem: How to mock and inject this mock object while creating myActivity object through robolectric
Note: This is existing Activity and I don't have much freedom to modify the Activity code to large extend. Also, we are using Mockito framework for mocking so it would be great if you give example using Mockito.
Here is my sample code where I try to use Robolectric with Mockito but it fails to work:
@RunWith(RobolectricTestRunner.class)
public class myActivityTest {
@Mock
private StorageManager storageManager;
@InjectMocks
MyActivity myActivity;
@Before
public void setUp() {
ActivityController<MyActivity> activityController = Robolectric.buildActivity(MyActivity.class);
myActivity = activityController.get();
// when(registrationActivity.GetMetricManager()).thenReturn(mock(MetricsManager));
initMocks(this);
activityController.setup();
}
}
I have tried the solution suggested below but now I am getting this error:
I have modified my code as you suggested and it is throwing below error. while executing this line ActivityController activityController = Robolectric.buildActivity(TestMyActivity.class);
java.lang.RuntimeException: java.lang.NoSuchMethodException: Tests$TestMyActivity.()
at org.robolectric.util.ReflectionHelpers.callConstructor(ReflectionHelpers.java:233)
at org.robolectric.util.ActivityController.of(ActivityController.java:27)
at org.robolectric.Robolectric.buildActivity(Robolectric.java:42)
at Tests$TestMyActivity.setUp(RegistrationTest.java:89)
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.RunBefores.evaluate(RunBefores.java:24)
First that StorageManager
is not a field or passed by constructor so @InjectMocks
doesn't have any effect.
I would refactor Activity to use better DI but a simple win would be:
public class MyActivity extends ... {
@VisibleForTest
@RestrictTo(Scope.TESTS)
protected StorageManager GetStorageManager() {
...
}
}
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class MyActivityTest {
@Mock
private StorageManager storageManagerMock;
MyActivity myActivity;
@Before
public void setUp() {
initMocks(this);
ActivityController<TestMyActivity> activityController = Robolectric.buildActivity(TestMyActivity.class);
myActivity = activityController.get();
// when(registrationActivity.GetMetricManager()).thenReturn(mock(MetricsManager));
activityController.setup();
}
...
public class TestMyActivity extends MyActivity {
protected StorageManager GetStorageManager() {
return storageManagerMock;
}
}
}
This should work with small modifications.
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