Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

robolectric - how to mock and inject a business class while creating Activity object

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)
like image 341
AvtarSohi Avatar asked Oct 17 '22 17:10

AvtarSohi


1 Answers

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.

like image 157
Eugen Martynov Avatar answered Oct 20 '22 20:10

Eugen Martynov