robolectric - 如何在创建 Activity 对象时模拟和注入业务 class
robolectric - how to mock and inject a business class while creating Activity object
我的任务是为现有的 Android activity 编写单元测试,而编写的代码并未遵循单元测试(紧耦合)。
场景:我有一个 class StroageManager,它在 MyActivity onCreate 方法中被实例化。
@Override
protected void onCreate(Bundle savedInstanceState)
{
StorageManager storagemanager = GetStorageManager(); // return new object of stroage manager
super.onCreate(savedInstanceState);.....
...
}
为了通过 Robolectric 创建 activity 的实例,我需要在设置 MyActivity.
之前在我的测试中模拟它
问题:如何在通过robolectric
创建我的Activity对象时模拟和注入这个模拟对象
注意:这是现有的 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: 测试$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.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)
首先,StorageManager
不是字段或由构造函数传递,因此 @InjectMocks
没有任何效果。
我会重构 Activity 以使用更好的 DI,但一个简单的胜利是:
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;
}
}
}
稍作修改即可使用。
我的任务是为现有的 Android activity 编写单元测试,而编写的代码并未遵循单元测试(紧耦合)。
场景:我有一个 class StroageManager,它在 MyActivity onCreate 方法中被实例化。
@Override
protected void onCreate(Bundle savedInstanceState)
{
StorageManager storagemanager = GetStorageManager(); // return new object of stroage manager
super.onCreate(savedInstanceState);.....
...
}
为了通过 Robolectric 创建 activity 的实例,我需要在设置 MyActivity.
之前在我的测试中模拟它问题:如何在通过robolectric
创建我的Activity对象时模拟和注入这个模拟对象注意:这是现有的 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: 测试$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.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)
首先,StorageManager
不是字段或由构造函数传递,因此 @InjectMocks
没有任何效果。
我会重构 Activity 以使用更好的 DI,但一个简单的胜利是:
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;
}
}
}
稍作修改即可使用。