<b>本文讲的是[译] 通过测试来解耦 Activity,</b>
本系列博文是关于 android-centric 架构的可测试性和其它问题之间的联系的,而这些问题正导致 Android 开发者们排斥这种架构。这些博文也涉及单元测试怎样试图告诉我们:<code>Activity</code> 和 <code>Fragment</code> 不是应用的最佳构件,因为它们迫使我们写出高耦合和低内聚的代码。
我们想要测试的“目标代码”,做了以下工作:当用户进入展示所有 Google I/O session 的地图界面时,app 会请求当前位置。如果用户拒绝提供定位权限,我们会弹出一个 toast 来提示用户已禁用此权限。这是其中的截图:
拒绝请求的 toast
这是实现代码:
让我们尝试测试下这些代码,我们的测试代码看起来是这样的:
当然你很希望能知道 <code>assertToastDisplayed()</code> 是怎么实现的。重点来了:我们不会直接实现该方法。为了避免实现后再重构我们的代码,我们需要使用 Roboelectric 和 Powermock。(译者注:Roboelectric 和 Powermock 均为测试框架)
我们在 <code>MapActivity</code> 里面的代码逻辑和 <code>Toast</code> 紧密地耦合在一起。
这之间的耦合驱使我们使用 Roboelectric 来模拟 android 行为和 powermock 来模拟静态的<code>Toast.makeText</code> 方法。作为替换,让我们以测试为驱动来去除耦合。
为了让我们重构有个方向,我们先写测试。这将确保我们的新类已经解耦。为了避免使用 Roboelectric 框架,我们需要在这特殊情况下创建一个新类,但是通常来说,我们只需重构已存在的类来解耦。
我们已经介绍过 <code>OnPermissionResultListener</code>,它的工作就是处理用户对 app 请求权限的反应。代码如下:
我们把对 <code>MapFragment</code> 和 <code>Toast</code> 的调用替换为对 <code>PermittedView</code> 里面方法的调用,这个对象通过构造函数来传递。<code>PermittedView</code> 是一个接口:
它在 <code>MapActivity</code> 里实现:
这也许不是最好的解决方案,但是这能让我们抓住可以在哪里测试这一重心。这要求<code>OnPermissionResultListener</code> 降低和 <code>PermittedView</code> 的耦合度。解耦 == 显而易见的进步。
对于这一点,一些读者可能会有所怀疑。“这样真的算优化代码吗?”他们会大惑不解。有两点理由可以确认为什么这样设计更好。
(无论我给出哪一个理由,你都会发现其解释是“因为它的可测试性更好,所以它设计得更好”,这是一个很重要的原因。)
snackbar 拒绝请求
这是一个小改变,但是因为我们已经把 <code>OnPermissionResultListener</code> 从 <code>PermittedView</code> 中分离出来,我们可以只专注于改变 <code>PermittedView</code> 在 <code>MapActivity</code> 里面的实现,而无需担心<code>OnPermissionResultListener</code>。
这是我们改变代码后的样子,使用他们的 <code>PermissionUtils</code> 类来显示 <code>SnackBar</code>。
请再留意,我们可以不用考虑 <code>OnPermissionResultListener</code> 就直接改变其内容。这实际就是 Larry Constantine 在 70 年代提出对耦合这一概念的定义:
我们尽力让系统解耦。。。这样我们就能研究(或者调试、维护)其中一个模块而无需考虑系统中的其他模块 –Edward Yourdon and Larry Constantine, Structured Design
另一个“为什么实际上通过我们的测试来迫使我们解耦是一件好事”的有趣原因是:耦合通常会导致重复。Kent Beck 曾对此有相关看法:
依赖是任意规模的软件开发的重点问题。。。如果依赖成为了问题,这就会体现在重复上。 -Kent Beck, TDD By Example, pg 7.
所以,当我们难以测试 <code>Activity</code> 和 <code>Fragment</code>时,通常是因为我们的测试尝试告诉我们所写的代码耦合度太高。测试对耦合度的警告通常以我们无法对代码做出断言的形式表现出来。
当我们听从我们的测试时,与其通过 Roboelectric 和 powermock 替换测试代码,不如改变被测代码,让其耦合度降低,这样我们就能更容易改代码和有更多的机会去重。
这也可能表现为无法让你的被测代码在测试中以一个正确的状态表现出来。例如我们在本篇中所看到的。
<b></b>
<b>原文发布时间为:2017年5月11日</b>
<b>本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。</b>