Android 利用机器人分子改变构型
为了跨配置更改保留异步任务,我使用了一个基于片段的解决方案和setRetainInstance(true),它托管每个异步任务并回调侦听活动,类似于此解决方案 最终,目的是使用Robolectric在整个配置更改过程中测试AsyncTask的保留功能,但我需要从正确设置实际配置更改开始。然而,我似乎无法模拟配置更改期间发生的确切引用行为Android 利用机器人分子改变构型,android,android-fragments,android-lifecycle,robolectric,android-testing,Android,Android Fragments,Android Lifecycle,Robolectric,Android Testing,为了跨配置更改保留异步任务,我使用了一个基于片段的解决方案和setRetainInstance(true),它托管每个异步任务并回调侦听活动,类似于此解决方案 最终,目的是使用Robolectric在整个配置更改过程中测试AsyncTask的保留功能,但我需要从正确设置实际配置更改开始。然而,我似乎无法模拟配置更改期间发生的确切引用行为 Real-app:运行Real-app时,在配置更改时,活动会被销毁并重新创建,而片段会被保留,因此它似乎正在工作。我可以通过检查配置更改前后的引用(下面使用
Real-app:运行Real-app时,在配置更改时,活动会被销毁并重新创建,而片段会被保留,因此它似乎正在工作。我可以通过检查配置更改前后的引用(下面使用的示例引用)来了解这一点:
- Real app,之前: 活动:abc 片段:xyz
- Real app,之后: 活动:bca 片段:xyz(正确保留并重新连接)
案例1:在Robolectric测试中对活动运行recreate()时,该活动似乎没有正确地重新创建其实例(尽管文档称该方法执行所有生命周期调用):
- 具有recreate()的Robolectric,之前: 活动:abc 片段:xyz
- 带recreate()的Robolectric,在 活动:abc 片段:xyz
案例2:如果我基于单个生命周期调用创建测试:
mActivityController = Robolectric.buildActivity(AsyncTaskTestActivity.class).attach().create().start().resume().visible();
mActivityController.pause().stop().destroy();
mActivityController = Robolectric.buildActivity(AsyncTaskTestActivity.class).attach().create().start().resume().visible();
在此版本中,活动似乎从零开始完全被替换,但片段也被替换:
- 具有单独生命周期调用的Robolectric,在 活动:abc 片段:xyz
- 具有单独生命周期调用的Robolectric,在 活动:bca 片段:yzx
看起来我要么重用相同的活动(案例1),要么用新实例替换所有内容,好像没有底层应用程序保留片段(案例2) 问题:我有没有办法设置我的Robolectric测试来模拟我在实际Android环境中运行应用程序时得到的参考结果(根据实际应用程序结果),或者我是否被困于创建单独的测试应用程序或解决Robotium功能测试?我试着这样做,但得到了与我的案例2相同的结果
提前谢谢 我已经研究了一下,并使用Robolectric 3.0和Mockito提出了一个解决方案:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.KITKAT, shadows = {ExampleActivityTest.ExampleActivityShadow.class})
public class ExampleActivityTest {
@Mock
private FragmentManager fragmentManagerMock;
@Before
public void setup() {
initMocks(this);
setupFragmentManagerMock();
}
@Test
public void testRestoreAfterConfigurationChange() {
// prepare
ActivityController<ExampleActivity> controller = Robolectric.buildActivity(ExampleActivity.class);
ExampleActivity activity = controller.get();
ExampleActivityShadow shadow = (ExampleActivityShadow) Shadows.shadowOf(activity);
shadow.setFragmentManager(fragmentManagerMock);
ActivityController<ExampleActivity> controller2 = Robolectric.buildActivity(ExampleActivity.class);
ExampleActivity recreatedActivity = controller2.get();
ExampleActivityShadow recreatedActivityShadow = (ExampleActivityShadow) Shadows.shadowOf(recreatedActivity);
recreatedActivityShadow.setFragmentManager(fragmentManagerMock);
// run & verify
controller.create().start().resume().visible();
activity.findViewById(R.id.inc_button).performClick();
activity.findViewById(R.id.inc_button).performClick();
assertEquals(2, activity.lostCount.count);
assertEquals(2, activity.retainedCount.count);
Bundle bundle = new Bundle();
controller.saveInstanceState(bundle).pause().stop().destroy();
controller2.create(bundle).start().restoreInstanceState(bundle).resume().visible();
assertEquals(0, recreatedActivity.lostCount.count);
assertEquals(2, recreatedActivity.retainedCount.count);
}
private void setupFragmentManagerMock() {
final HashMap<String, Fragment> fragments = new HashMap<>();
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return fragments.get(invocation.getArguments()[0]);
}
}).when(fragmentManagerMock).findFragmentByTag(anyString());
final HashMap<String, Fragment> fragmentsToBeAdded = new HashMap<>();
final FragmentTransaction fragmentTransactionMock = mock(FragmentTransaction.class);
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
fragmentsToBeAdded.put((String) invocation.getArguments()[1], (Fragment) invocation.getArguments()[0]);
return fragmentTransactionMock;
}
}).when(fragmentTransactionMock).add(any(Fragment.class), anyString());
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
fragments.putAll(fragmentsToBeAdded);
return null;
}
}).when(fragmentTransactionMock).commit();
when(fragmentManagerMock.beginTransaction()).thenReturn(fragmentTransactionMock);
}
@Implements(Activity.class)
public static class ExampleActivityShadow extends ShadowActivity {
private FragmentManager fragmentManager;
@Implementation
public FragmentManager getFragmentManager() {
return fragmentManager;
}
public void setFragmentManager(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
}
}
@RunWith(RobolectricGradleTestRunner.class)
@配置(常量=BuildConfig.class,sdk=Build.VERSION\u CODES.KITKAT,shadows={ExampleActivityTest.ExampleActivityShadow.class})
公共类ExampleActivityTest{
@嘲弄
私人FragmentManager fragmentManagerMock;
@以前
公共作废设置(){
initMocks(这个);
setupFragmentManagerMock();
}
@试验
public void testRestoreAfterConfigurationChange(){
//预备
ActivityController控制器=Robolectric.buildActivity(ExampleActivity.class);
ExampleActivity=controller.get();
ExampleActivityShadow=(ExampleActivityShadow)Shadows.shadowOf(活动);
setFragmentManager(fragmentManagerMock);
ActivityController控制器2=roblectric.buildActivity(ExampleActivity.class);
ExampleActivity recreatedActivity=controller2.get();
ExampleActivityShadow recreatedActivityShadow=(ExampleActivityShadow)Shadows.shadowOf(recreatedActivity);
重新创建活动Shadow.setFragmentManager(fragmentManagerMock);
//运行并验证
controller.create().start().resume().visible();
activity.findViewById(R.id.inc_按钮).performClick();
activity.findViewById(R.id.inc_按钮).performClick();
assertEquals(2,activity.lostCount.count);
assertEquals(2,activity.retainedCount.count);
Bundle=新Bundle();
controller.saveInstanceState(bundle.pause().stop().destroy();
controller2.create(bundle.start().restoreInstanceState(bundle.resume().visible();
assertEquals(0,recreatedActivity.lostCount.count);
assertEquals(2,recreatedActivity.retainedCount.count);
}
私有void setupFragmentManagerMock(){
final HashMap fragments=new HashMap();
doAnswer(新答案){
@凌驾
公共对象应答(InvocationMock调用)抛出Throwable{
返回fragments.get(invocation.getArguments()[0]);
}
}).when(fragmentManagerMock).findFragmentByTag(anyString());
final HashMap fragmentsToBeAdded=新HashMap();
final FragmentTransaction fragmentTransactionMock=mock(FragmentTransaction.class);
doAnswer(新答案){
@凌驾
公共对象应答(InvocationMock调用)抛出Throwable{
fragmentsToBeAdded.put((字符串)调用.getArguments()[1],(片段)调用.getArguments()[0]);
返回fragmentTransactionMock;
}
}).when(fragmentTransactionMock).add(any(Fragment.class),anyString());
doAnswer(新答案){
@凌驾
公共对象应答(InvocationMock调用)抛出Throwable{
碎块。碎块(碎块加碎);
返回null;
}
}).when(fragmentTransactionMock).commit();
当(fragmentManagerMock.beginTransaction())。然后返回(fragmentTransactionMock);
}
@实施(A)
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.KITKAT, shadows = {ExampleActivityTest.ExampleActivityShadow.class})
public class ExampleActivityTest {
@Mock
private FragmentManager fragmentManagerMock;
@Before
public void setup() {
initMocks(this);
setupFragmentManagerMock();
}
@Test
public void testRestoreAfterConfigurationChange() {
// prepare
ActivityController<ExampleActivity> controller = Robolectric.buildActivity(ExampleActivity.class);
ExampleActivity activity = controller.get();
ExampleActivityShadow shadow = (ExampleActivityShadow) Shadows.shadowOf(activity);
shadow.setFragmentManager(fragmentManagerMock);
ActivityController<ExampleActivity> controller2 = Robolectric.buildActivity(ExampleActivity.class);
ExampleActivity recreatedActivity = controller2.get();
ExampleActivityShadow recreatedActivityShadow = (ExampleActivityShadow) Shadows.shadowOf(recreatedActivity);
recreatedActivityShadow.setFragmentManager(fragmentManagerMock);
// run & verify
controller.create().start().resume().visible();
activity.findViewById(R.id.inc_button).performClick();
activity.findViewById(R.id.inc_button).performClick();
assertEquals(2, activity.lostCount.count);
assertEquals(2, activity.retainedCount.count);
Bundle bundle = new Bundle();
controller.saveInstanceState(bundle).pause().stop().destroy();
controller2.create(bundle).start().restoreInstanceState(bundle).resume().visible();
assertEquals(0, recreatedActivity.lostCount.count);
assertEquals(2, recreatedActivity.retainedCount.count);
}
private void setupFragmentManagerMock() {
final HashMap<String, Fragment> fragments = new HashMap<>();
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return fragments.get(invocation.getArguments()[0]);
}
}).when(fragmentManagerMock).findFragmentByTag(anyString());
final HashMap<String, Fragment> fragmentsToBeAdded = new HashMap<>();
final FragmentTransaction fragmentTransactionMock = mock(FragmentTransaction.class);
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
fragmentsToBeAdded.put((String) invocation.getArguments()[1], (Fragment) invocation.getArguments()[0]);
return fragmentTransactionMock;
}
}).when(fragmentTransactionMock).add(any(Fragment.class), anyString());
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
fragments.putAll(fragmentsToBeAdded);
return null;
}
}).when(fragmentTransactionMock).commit();
when(fragmentManagerMock.beginTransaction()).thenReturn(fragmentTransactionMock);
}
@Implements(Activity.class)
public static class ExampleActivityShadow extends ShadowActivity {
private FragmentManager fragmentManager;
@Implementation
public FragmentManager getFragmentManager() {
return fragmentManager;
}
public void setFragmentManager(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
}
}