Android 利用机器人分子改变构型

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时,在配置更改时,活动会被销毁并重新创建,而片段会被保留,因此它似乎正在工作。我可以通过检查配置更改前后的引用(下面使用

为了跨配置更改保留异步任务,我使用了一个基于片段的解决方案和setRetainInstance(true),它托管每个异步任务并回调侦听活动,类似于此解决方案

最终,目的是使用Robolectric在整个配置更改过程中测试AsyncTask的保留功能,但我需要从正确设置实际配置更改开始。然而,我似乎无法模拟配置更改期间发生的确切引用行为


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