使用Robolectric配置更改 [英] Configuration change using Robolectric

查看:225
本文介绍了使用Robolectric配置更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要保留我的AsyncTasks跨越配置变化,我用setRetainInstance(真)基于片段的解决方案,它承载每一个的AsyncTask和回调监听活动,类似这种解决方案的http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

To retain my AsyncTasks across configuration changes, I use a fragment-based solution with setRetainInstance(true), which hosts each AsyncTask and calls back to a listening Activity, similar to this solution http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

最后,目的是在整个使用Robolectric配置更改测试的AsyncTask的保留功能,但我需要先正确设置实际的配置更改。但是,似乎我无法模仿的配置变化过程中出现的具体参考的行为。

Ultimately, the purpose is to test the AsyncTask's retention functionality throughout configuration changes using Robolectric, but I need to start with setting up the actual configuration change correctly. However, it seems I can't mimic the exact reference behavior that occurs during a configuration change.

真正的应用程序::当运行一个真正的应用程序,在配置更改,活动被破坏并重新创建,而片段被保留,所以它似乎是工作。我可以通过配置更改之前和之后检查它们的引用(以下使用例如参考文献)看到这一点:

Real app: When running a real app, on configuration change, the Activity is destroyed and recreated while the Fragment is retained, so it seems to be working. I can see this by checking their references before and after the configuration change (example references used below):


  • 真正的应用程序,在此之前:
    活动: ABC
    片段: XYZ

真正的应用程序后:
活动: BCA
片段: XYZ(妥善保留,并重新连接)

Real app, after: Activity: bca Fragment: xyz (properly retained and reattached)

案例1:当运行在Robolectric测试活动重新创建(),但是,活动似乎并未有其背景正确地重新创建(尽管文件称该方法执行所有生命周期话费):

Case 1: When running recreate() on the Activity in the Robolectric test, however, the Activity doesn't seem to have its instance properly recreated (despite the docs saying the method performs all the lifecycle calls):

mActivityController =
Robolectric.buildActivity(AsyncTaskTestActivity.class).attach().create().start().resume().visible();

mActivity = mActivityController.get();
mActivity.recreate();


  • Robolectric与重新创建()之前:
    活动: ABC
    片段: XYZ

    Robolectric与重新创建()后,
    活动: ABC
    片段: XYZ

    Robolectric with recreate(), after Activity: abc Fragment: xyz

    这使我相信,一个新的活动实例未正确地创建和复位功能,因此并没有在真正发生的方式。

    This leads me to believe that a new Activity instance isn't properly created and the reattachment functionality therefore hasn't happened in a real way.

    案例2:如果我创建基于个体生命周期测试调用来代替:

    Case 2: If I create the test based on individual lifecycle calls instead:

    mActivityController = Robolectric.buildActivity(AsyncTaskTestActivity.class).attach().create().start().resume().visible();
    mActivityController.pause().stop().destroy();
    mActivityController = Robolectric.buildActivity(AsyncTaskTestActivity.class).attach().create().start().resume().visible();
    

    在这个版本中,似乎得到活动从头开始全面更换,但如此也做的片段:

    In this version, it seems the Activity gets fully replaced from scratch, but so does also the Fragment:


    • Robolectric有独立的生命周期中调用,前
      活动: ABC
      片段: XYZ

    Robolectric有独立的生命周期的电话,后
    活动: BCA
    片段: YZX

    Robolectric with separate lifecycle calls, after Activity: bca Fragment: yzx

    看来我要么重复使用相同的活动(情况1)或新的实例代替一切,如果有任何保留片段(案例2)。没有潜在应用

    It seems I'm either reusing the same Activity (case 1) or replacing everything with new instances, as if there is no underlying Application that retains the Fragment (case 2).

    问:有什么办法,我可以设置我Robolectric测试,以模仿参照结果运行在实际的Andr​​oid环境中的应用程序时(按照真正的应用程序的结果),我得到的,或我会坚持无论是创建一个独立的测试应用程序或Robotium功能测试解决?我试图做这样的 http://stackoverflow.com/a/26468296 但得到相同的结果,我的情况2。

    Question: is there any way I can set up my Robolectric test to mimic the reference result that I get when running the app in an actual Android environment (as per the Real app result), or am I stuck with either creating a separate test app or settling with Robotium functional tests? I tried to do it like this http://stackoverflow.com/a/26468296 but got the same result as my case 2.

    在此先感谢!

    推荐答案

    我身边有位出场并使用Robolectric 3.0和一个的Mockito解决想出了:

    I have played around a bit and came up with a solution using Robolectric 3.0 and 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;
            }
        }
    }
    

    请注意,我只是嘲笑FragmentManager(的BeginTransaction() findFragmentByTag())和FragmentTransaction的方法(添加()提交()),我在我的code使用的,所以你可能需要根据您的code扩大这些。

    Note that I have only mocked the methods of FragmentManager (beginTransaction() and findFragmentByTag()) and FragmentTransaction (add() and commit()) that I use in my code, so you might need to expand these depending on your code.

    我还没有做Robolectric太多的工作了,所以有可能是一个更优雅的解决这一问题,但是对我的作品现在。

    I haven't done too much work with Robolectric yet, so there may be a more elegant solution to this, but this works for me for now.

    您可以看到完整的源代码code和项目设置在这里: https://github.com/rgeldmacher /皮带(如果你仍然需要保留对象可能是值得一试;))

    You can see the full source code and project setup here: https://github.com/rgeldmacher/leash (might be worth a look if you still need to retain objects ;) )

    这篇关于使用Robolectric配置更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆