3

我的 Robolectric 单元测试有问题。

当侦听器使用该方法时,我可以毫无问题地断言单击启动了新活动startActivity( Intent )

但是,当使用该方法启动一个新活动时,Robolectric 似乎遇到了麻烦startActivityForResult(Intent, int):在代码中放置一些中断让我发现该活动没有启动(并且只是更改方法startActivity( Intent )使断言通过)。

这正常吗?很遗憾,因为我的应用程序的第一个活动使用startActivityForResult(Intent, int).

有人设法用这种启动活动的方式进行测试吗?

谢谢你的帮助 ..

4

2 回答 2

4

对您的问题的简短回答是,由于 Robolectric 将 Android 类转换为在 JVM 中执行的代码的方式,它们的许多功能并没有像您预期的那样运行。许多系统回调不会执行,您将不得不依赖 Robolectric 在其 Shadow 类实现中提供的功能。(请参阅@Steven_BDawg 提供的链接)。

长答案:也许可以在一个大型测试中实现整个流程,但这不是框架的设计目的。

一般而言,Robolectric 和单元测试并不意味着以您描述的方式使用。 维基百科上的单元测试页面指出,可以将单元视为应用程序中最小的可测试部分。一个单元测试套件应该包含许多轻量级测试,其中每个测试都会隔离应用程序中的一些功能并确保其正常工作。

考虑一个包含两个活动 A 和 B 的基本应用程序。活动 A 显示有关主题的一些信息,活动 B 允许用户选择要在 A 中显示的主题。当用户从活动 A 移动到活动 B 时,B 得到调用startActivityForResult()并应返回 A 与所选主题。

现在假设我们要对 A 从 B 获取结果并显示数据的流程进行单元测试。我们可以将其分解为两个测试:

  1. Activity Under Test - Activity A。在我们的测试中,我们将创建一个 Activity A 的新实例。在 Robolectric 测试中,我们创建我们期望 B 返回到 A 的 Intent,并receiveResult()为 A 调用 shadow 方法,填写结果代码为 OK 和此 Intent 的参数。之后receiveResult(),运行您的断言。您现在知道 Activity A 正确处理了结果!
  2. Activity Under Test - Activity B。在我们的测试中,我们将创建一个 Activity B 的新实例,将其设置为好像它是为 Activity A 的结果启动的一样。在 Robolectric 测试中,我们将执行选择所需的所有操作数据,创建我们将发回的意图,然后对意图运行断言以确保它被正确创建。

这是一个非常简单的例子。这两个步骤可能会分解成更多的测试,因为每个单元测试应该只测试你的应用程序可以分解的最小功能单元。该示例主要是帮助您以单元测试的方式开始思考。我发现随着我对单元测试理解的加深,我编写代码的方式也发生了变化。我尽量避免以这样的方式编写方法和类,因为它们做了太多工作并且无法正确进行单元测试。根据经验,易于单元测试的代码会执行非常具体的操作,这在第一次阅读代码时很明显。

最后,如果您想更进一步,模拟框架可以极大地帮助您进行单元测试。 Mockito是我过去成功使用的一个模拟框架。模拟框架的目的是创建您严格控制其行为的存根对象。Mockito(或任何其他 Mocking 框架)将允许您定义一个从您需要的任何类型扩展的对象,并且只实现您需要的方法。您将能够直接控制对任何这些方法调用的响应。这有助于单元测试,因为唯一真正的您需要的对象是被测对象;通过模拟所有其他对象,您将更好地了解被测对象是否行为正常,因为所有其他行为都是由您(测试人员)明确定义的。(是的,这确实会导致大量额外的代码,但这就是优秀单元测试人员的生活。但是,如前所述,随着您对单元测试越来越熟悉,您可能会发现自己编写的方法需要更少的模拟和更有利于编写测试。一些程序员甚至会在编写代码之前编写单元测试,以保持代码紧凑并专注于单一目的)

希望这可以帮助!

于 2013-01-23T21:24:54.943 回答
3

我为你做了一些谷歌搜索。我不知道这是否一定会帮助你,但我认为这是一个好的开始! Roboelectric:测试 startActivityForResult() 和 onActivityResult()

于 2013-01-23T15:07:35.400 回答