使用 Robolectric 更改配置

2024-03-31

为了在配置更改时保留 AsyncTasks,我使用基于片段的解决方案和 setRetainInstance(true),它托管每个 AsyncTask 并回调侦听 Activity,类似于此解决方案http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html

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


真实应用程序:当运行真实的应用程序时,在配置更改时,活动将被销毁并重新创建,而片段将被保留,因此它似乎正在工作。我可以通过检查配置更改之前和之后的参考来看到这一点(下面使用的示例参考):

  • 真实的应用程序,之前:活动: abc 分段: xyz

  • 真实的应用程序,之后:活动: bca 分段:xyz(正确保留并重新连接)


Case 1:然而,当在 Robolectric 测试中的 Activity 上运行 recreate() 时,该 Activity 似乎没有正确重新创建其实例(尽管文档说该方法执行所有生命周期调用):

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

mActivity = mActivityController.get();
mActivity.recreate();
  • Robolectric 与 recreate() 之前:活动: abc 分段: xyz

  • Robolectric 与 recreate() 之后活动: abc 分段: xyz

这使我相信新的 Activity 实例未正确创建,因此重新附加功能并未真正发生。


Case 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();

在这个版本中,似乎 Activity 被从头开始完全替换,但 Fragment 也是如此:

  • Robolectric 具有单独的生命周期调用,之前活动: abc 分段: xyz

  • Robolectric 具有单独的生命周期调用,之后活动: bca 分段: yzx


看来我要么重用相同的 Activity(情况 1),要么用新实例替换所有内容,就好像没有底层应用程序保留 Fragment(情况 2)一样。

问题:有什么方法可以设置我的 Robolectric 测试来模拟在实际 Android 环境中运行应用程序时获得的参考结果(根据真实应用程序结果),或者我是否坚持创建一个单独的测试应用程序或解决与 Robotium 功能测试?我试着这样做https://stackoverflow.com/a/26468296 https://stackoverflow.com/a/26468296但得到了与我的案例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;
        }
    }
}

请注意,我只模拟了 FragmentManager 的方法(beginTransaction() and findFragmentByTag()) 和 FragmentTransaction (add() and commit()),我在代码中使用,因此您可能需要根据您的代码扩展它们。

我还没有对 Robolectric 做过太多工作,所以可能有一个更优雅的解决方案,但这目前对我有用。

您可以在此处查看完整的源代码和项目设置:https://github.com/rgeldmacher/leash https://github.com/rgeldmacher/leash(如果您仍然需要保留对象,可能值得一看;))

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Robolectric 更改配置 的相关文章

  • ExtJS GridPanel 中的垂直滚动条

    我正在开发一个项目 其中页面上有一个 GridPanel 该面板可以显示任意数量的行 并且我设置了 autoHeight 属性 这会导致 GridPanel 扩展以适合行数 我现在想要一个水平滚动条 因为在某些分辨率下 并非所有列都会显示
  • Microsoft Graph API 调用无限期挂起

    我正在尝试使用 Microsoft Graph 查询 Azure Active Directory 用户信息 我可以很好地进行身份验证 但是当我尝试查询用户信息时client Users我的应用程序无限期挂起 没有超时 没有错误 只是挂起
  • 使用和不使用 SciPy 计算 k 组合的数量

    我对这个函数感到困惑combSciPy 的 http docs scipy org doc scipy 0 14 0 reference generated scipy misc comb html看起来比简单的 Python 实现要慢 这
  • 如何将 Redux DevTools 扩展添加到我的 React-Redux 商店?

    我正在尝试将 Redux DevTools Chrome 扩展添加到我的 redux 商店 并在此处进行描述 http extension remotedev io http extension remotedev io 这是我的商店 le
  • Google 地图 v3 信息窗口在地图视口外打开

    如果单击地图视口顶部附近的标记 信息窗口将加载到可视区域之外 并且必须拖动地图才能查看信息窗口内容 理想情况下 我不希望地图自动平移 有没有办法以不同的方向加载信息窗口 例如如果标记位于视口的顶部 则以向下的方向显示信息窗口 不 你不能以不
  • Xcode 调试器显示错误的变量值

    我之前问过类似的问题here https stackoverflow com q 53092448 1187415 这个版本有更简单的例子 更新摘要 Xcode 在调试器变量部分中为每个字符串显示 FAIL Swift print 语句显示
  • Cassandra 中的数据分布

    我听说过 Cassandra 及其发行版 其实想知道数据在整个集群中是如何分布的现象 我的意思是 Cassandra 如何决定哪些节点拥有哪些数据 如果您了解 HashTable 数据结构以及 Hashtable 中如何进行哈希处理 那么这
  • 为什么 SQL Server 不推荐使用 SET ANSI_PADDING OFF?

    根据 MSDN BOL 在线书籍 SET ANSI PADDING http msdn microsoft com en us library ms187403 aspx 在 Microsoft SQL Server 的未来版本中 ANSI
  • 并行 Haskell - GHC GC 火花

    我有一个正在尝试并行化的程序 带有可运行代码的完整粘贴here http lpaste net 101528 我进行了分析 发现大部分时间都花在findNearest这本质上是一个简单的foldr超过一个大Data Map findNear
  • 是否可以将 Vagrant 与 intelliJ 一起使用?

    假设我正在使用 Java 并使用 IntelliJ 来执行构建和部署等操作以及其他类似操作 我以前没有使用过 Vagrant 但是在运行 Vagrant 实例时是否可以继续使用 IntelliJ 进行构建和部署 是的 您可以将 IDE 与
  • 每次都在django查询数据库中过滤查询集吗?

    想象一下我有以下代码 qs Users objects all list for i in range 10 list append qs filter age i 这里过滤器被调用 10 次 它是连接到数据库 10 次还是第一次使用过滤器
  • 如何对数字进行排序? [复制]

    这个问题在这里已经有答案了 下面是代码 Is the sortNumber对数字进行排序的函数 a 和 b 是什么意思以及为什么存在 为什么sortNumber in n sort sortNumber 没有指定任何参数a and b Ja
  • 从 Bigcommerce 的浏览器内存中删除注入的分析库?

    我们如何删除这个脚本注入器系统并清除内存中的函数 简报 最近 Bigcommerce 的不法分子以 监控 为幌子创建了一个分析注入器 JS 该注入器被锁定在全局变量中 他们在未经任何 OP 同意的情况下将其推广到所有 50 000 家前台商
  • 是什么让热部署成为“难题”?

    在工作中 我们经常遇到这样的问题 永久代内存不足 http www jroller com agileanswers entry preventing java s java lang例外 团队负责人认为这是 JVM 中的一个错误 与代码的
  • JavaScript Uncaught ReferenceError:jQuery 未定义;未捕获的引用错误:$未定义[重复]

    这个问题在这里已经有答案了 这是我的小提琴http jsfiddle net 4vaxE 35 http jsfiddle net 4vaxE 35 它在我的小提琴中工作得很好 但是 当我将其转移到dreamweaver时 它无法工作 我在
  • 高图表的分散工具提示未显示

    我有一个散点图和条形图 我无法查看酒吧上方散点的工具提示 这是小提琴http jsfiddle net tZ9Rt http jsfiddle net tZ9Rt 我正在使用这两个系列 series type scatter index 2
  • 我可以使用 VBA 将密码“传递”到 Excel 中的外部数据库连接吗?

    我正在尝试使用 VBA 隐藏我在 Excel 工作表中设置的数据连接的密码 由于 Excel 以纯文本形式存储外部数据源的密码 因此我想让 VBA 调用表的刷新并提供密码 我录制了刷新表格并输入密码的宏 但令我沮丧的是 它似乎省略了密码部分
  • 使用 Fetch 发生超时错误 - React Native

    我有一个正在运行的用户登录功能 但是 我想在获取时加入超时错误 有没有办法设置一个 5 秒左右的计时器 这样在这个时间之后就会停止尝试获取 否则 一段时间后我就会出现红屏 提示网络错误 userLogin var value this re
  • 直接或通过包含定义嵌套类

    假设我正在为我的家庭存储系统建模 我有很多不同类型的Container 而且我发现其中很多都有装饰品 因此我为这种常见情况设置了一些辅助代码 我的容器中有我的Mantlepiece and my Bookcase 我只在前者上存放装饰品 而
  • 当支持 SPDY 的浏览器收到 HTTP2 (H2) 响应时会发生什么?

    我的直觉是 支持 SPDY 的浏览器会将其视为 SPDY 响应 然而 我能找到的最多的是 H2 响应将优雅地降级到 HTTP1 1 的保证 我正在考虑以面向 H2 的方式提供资产 多个请求 无域分片等 但我确实需要支持一些非 H2 浏览器

随机推荐

  • Django 应用程序是否可以知道用户的 Windows 域名?

    我需要制作一个简单的知识库类型应用程序以在公司内部网络中使用 为了使最终用户使用起来简单快捷 我想部分跳过所有登录 因为它只对我们信任的内部网络用户可见 并自动从用户中提取域用户名并放入它进入数据库 不希望人们浪费时间手动输入他们的名字 他
  • 如何强制win10打开虚拟平板键盘?

    我有一个需要虚拟键盘的应用程序 但是 当我点击我的一些TextBoxes 它们不会使虚拟键盘出现 我尝试过使用这个 System Diagnostics Process Start osk exe 但这会打开另一个键盘 该键盘在TextBo
  • 在 onBackStackChanged() 内调用时,SDK 25.1.0 在 CommitNow 上崩溃。谷歌错误?

    我有一个活动 有 2 个片段FragmentMainOne and FragmentMainTwo每当onBackStackChanged 叫做 public class MainActivity extends AppCompatActi
  • 当小部件包装在 InteractiveViewer 中时,Flutter onPanStart 会延迟调用

    我只有一个简单的容器 其右侧中心有一个调整大小手柄 这意味着可以使用该手柄调整容器的大小 它被包裹在里面InteractiveViewer widget import package flutter material dart import
  • 使用nested_form获取对象值

    我有一个嵌套表单 订单付款 我想在编辑视图中测试嵌套表单 fields for 中的值 但问题是我无法检查每个 我只能这样做 您现在是否可以检查每个 例如 如果我理解这个问题 那么您正在编辑订单并拥有fields for对于付款并想要获取与
  • .c 文件中的 C99 内联函数

    我在 c 中定义了我的函数 没有标头声明 如下所示 inline int func int i return i 1 然后在下面的同一个文件中我使用它 i func i 在链接过程中 我得到了 对 func 的未定义引用 为什么 The i
  • Raspbian 的软浮动版本无法启动

    我在这里下载了 Raspbian 的硬浮动图像 http www raspberrypi org downloads http www raspberrypi org downloads 我将推荐的硬浮动映像复制到 SD 卡上 并且 Ras
  • VSCode 是否应该报告从编译中排除的 TS 文件的错误?

    我提交了这个错误报告 https github com Microsoft vscode issues 53733 issuecomment 403153218使用 VSCode 因为我已经排除了 spec编译中的文件 因为我不想将这些文件
  • 自动任务和静态任务有什么区别,为什么我们不能通过引用传递静态任务

    静态任务和自动任务有什么区别 program class ref int index value class holding values int ass array task assign value int value int inde
  • LinearSVC.coef_ 中的 n_classes 顺序

    我正在与 LinearSVC 合作将文本数据分为 3 类 输入数据是每个单词的 tfidf 分数 我有兴趣了解单词对分类的 贡献 第一个问题是我可以使用 coef 吗 文档指出 coef 数组 形状 n features 如果 n clas
  • 使用 cakephp 获取名称显示在下拉列表中

    我想在下拉列表中显示我们所有项目负责人的姓名 项目负责人只是公司的部分员工 这是我的表格 project leaders id hr employee id 1 18 projects id name project leader id 1
  • R 基本函数根据长度对字符串向量进行排序

    我想知道 R 基础包中是否已经有一个函数可以对字符串向量进行排序 同时考虑每个元素的长度 当然还有字典顺序 例如在一个sort调用一些包含您将拥有的年龄组的向量 v lt c 00 04 05 09 10 14 100 104 105 10
  • Matter.js 用于碰撞检测

    我对在这里提问还比较陌生 所以请耐心等待 我正在尝试使用 Matter js 作为主要物理引擎创建一个自上而下的驾驶游戏 我希望红色汽车与绿色方块相撞 然而 我仍然坚持知道如何在我的游戏中实现 Matter js 任何形式的回应将不胜感激
  • 如何在 R 中创建具有特定间隔的向量?

    我有一个关于创建向量的问题 如果我做a lt 1 10 a 的值为 1 2 3 4 5 6 7 8 9 10 我的问题是如何创建一个元素之间具有特定间隔的向量 例如 我想创建一个具有从 1 到 100 的值的向量 但仅以 5 为间隔进行计数
  • 如何将config.properties转换为键值对?

    我正在尝试将 java 属性文件转换为可以在 jquery 中使用的键值对 属性文件发送如下所示的信息 company1 Google company2 eBay company3 Yahoo 我想要这种形式 var obj company
  • Flutter - 主动检查是否按下了特殊键(如 ctrl)

    Question How to actively check if a certain decoration key is pressed like CTRL or SHIFT like if SomeKeyboardRelatedServ
  • 在 Spring Boot 应用程序的生产中使用 Tomcat

    作为 Spring Boot 的新手 我需要了解以下内容 因为我无法直接找到谷歌结果 他们在现实生活中真正使用哪些应用程序服务器来部署这些 Spring Boot 应用程序 Tomcat 真的被公司使用吗 如果是的话 他们是通过集群来实现的
  • 在 WCF 代理中实现 Ws 安全

    我已将基于轴的 wsdl 导入到 VS 2008 项目中作为服务参考 我需要能够传递安全详细信息 例如用户名 密码和随机数值 来调用基于轴的服务 我已经考虑过为 wse 做这件事 我知道世界讨厌它 那里没有问题 我对 WCF 的经验很少 但
  • 如何更新StackPanel的布局?

    问题是 如果您单击按钮并展开电话号码 堆栈面板和边框会展开 这很好 但如果您折叠它 堆栈面板和边框不会折叠
  • 使用 Robolectric 更改配置

    为了在配置更改时保留 AsyncTasks 我使用基于片段的解决方案和 setRetainInstance true 它托管每个 AsyncTask 并回调侦听 Activity 类似于此解决方案http www androiddesign