Robolectric - 如何在创建Activity对象时模拟和注入业务类

5
我的任务是为现有的Android活动编写单元测试,但代码并没有遵守单元测试(紧密耦合)的编写规范。
场景:我有一个类StorageManager,在MyActivity的onCreate方法中被实例化。
@Override
protected void onCreate(Bundle savedInstanceState) 
{            
 StorageManager storagemanager = GetStorageManager(); // return new object of stroage manager
 super.onCreate(savedInstanceState);.....
    ...
}

为了通过Robolectric创建活动实例,我需要在设置MyActivity之前在我的测试中对其进行模拟。
问题:如何在通过Robolectric创建myActivity对象时模拟并注入该模拟对象?
注意:这是现有的Activity,我没有太多修改Activity代码的自由。此外,我们使用Mockito框架进行模拟,如果您能给出使用Mockito的示例,那就太好了。
以下是我的示例代码,我尝试使用Robolectric和Mockito,但它无法正常工作:
@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();         
    }

我尝试使用下面建议的解决方案,但现在出现了以下错误:

我已按照您的建议修改了我的代码,但执行以下代码时发生错误。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)
1个回答

3

首先,StorageManager 不是一个字段或通过构造函数传递,因此 @InjectMocks 没有任何效果。

我建议重构 Activity 使用更好的依赖注入,但是一个简单的解决方案是:

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;
      }
   }
}

这应该可以通过微小的修改实现。

我已按照您的建议修改了我的代码,但在执行buildActivity方法时出现以下错误。 - AvtarSohi
谢谢Eugen@的回复,但是我在按照您的建议操作时仍然遇到了错误。您能否给我提供一个@InjectMocks的解决方案,因为我可以将该方法更改为字段,而这没有任何特殊之处,我可以使用setter和getter代替方法。 - AvtarSohi
可能应该将Activity类设置为静态的。 - Eugen Martynov
我可以通过使用daggerDI将Mocked Storagemanager注入到MyActivity类中来解决这个问题。 - AvtarSohi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接