移动应用遗留系统重构(6)- 测试篇
前言
上一篇移动应用遗留系统重构(5)- 重构方法篇我们分享了进行依赖解除的重构流程。主要为4个操作步骤,识别内聚包、解除依赖、移动、验收。同时最后也提出了一个问题,重构时如何保证功能的正确性,不会修改出新问题?
其实这个问题容易但又不简单。容易的是把修改得功能仔细测一篇保证所有功能正常就可以了。不简单的是如何全面、高效、可重复的执行这个过程。我们很容易联想到的方案就是自动化测试。但最大的问题是,对大部分遗留系统来说都是没有任何自动化测试。而且大量的坏味道代码,可测试性低,我们也很难补充充分的自动化测试。那么我们有什么折中的策略吗?
测试策略
我们先来看看Google Android开发者官网上对于测试的介绍,将不同的类型的测试分为三类测试(即小型、中型和大型测试)。
- 小型测试是指单元测试,用于验证应用的行为,一次验证一个类。
- 中型测试是指集成测试,用于验证模块内堆栈级别之间的互动或相关模块之间的互动。
- 大型测试是指端到端测试,用于验证跨越了应用的多个模块的用户操作流程。
前面提到对于遗留单体系统来说通常没有任何自动化测试,并且通常内部结构耦合严重,所以实施中小型的成本非常高。显然对于遗留系统,测试金字塔模型适用度较低。 所以对于遗留系统,可能比较适合的策略模型如下:
对于遗留单体系统,一个可行的思路是先补充中大型的测试,作为基本的冒烟测试,重构优化内部结构后再及时补充中小型测试。
CloudDisk示例
对于我们这个浓缩版的CloudDisk,界面上也比较简单。主要是有一个主界面,主界面上主要为文件、动态、用户。(后续的MV*重构篇会持续补充页面交互及逻辑)
我们可以设计一组UI的测试验证基本的功能。主要的几个测试点如下:
- 主界面能正常运行并显示3个Fragment
- 3个Fragment能正常显示
- 点击登录按钮,能够跳转到登录页面
测试设计的用例如下:
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SmokeTesting {
@Test
public void should_show_fragment_list_when_activity_launch() {
//given
ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
//when
onView(withText(R.string.tab_user)).perform(click());
//then
List fragments = activity.getSupportFragmentManager().getFragments();
assertThat(fragments.size() == 3);
assertThat(fragments.get(0) instanceof FileFragment);
assertThat(fragments.get(1) instanceof DynamicFragment);
assertThat(fragments.get(2) instanceof UserCenterFragment);
});
}
@Test
public void show_show_file_ui_when_click_tab_file() {
//given
ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
//when
onView(withText(R.string.tab_file)).perform(click());
//then
onView(withText("Hello file fragment")).check(matches(isDisplayed()));
});
}
@Test
public void show_show_dynamic_ui_when_click_tab_dynamic() {
//given
ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
//when
onView(withText(R.string.tab_dynamic)).perform(click());
//then
onView(withText("Hello dynamic fragment")).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
});
}
@Test
public void show_show_user_center_ui_when_click_tab_dynamic() {
//given
ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
//when
onView(withText(R.string.tab_user)).perform(click());
//then
onView(withText("Hello user center fragment")).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
});
}
@Test
public void show_show_login_ui_when_click_login_button() {
//given
ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
scenario.onActivity(activity -> {
Intents.init();
//when
onView(withId(R.id.fab)).perform(click());
//then
intended(IntentMatchers.hasComponent("com.cloud.disk.platform.login.LoginActivity"));
Intents.release();
});
}
}
复制代码
详细代码见Github提交
我们可以将用例运行在Robolectric上,提高反馈的速度,执行命令如下:
./gradlew testDebug --tests SmokeTesting
复制代码
测试执行结果如下:
当然实际的项目里情况更复杂,数据可能来自网络服务、数据库等等。我们还需要进行Mock。后续的MV*重构篇会持续补充常见坏味道示例代码及更多的自动化测试用例。
更多测试框架及设计可以参考Google官方
在 Android 平台上测试应用
总结
这一篇我们介绍了常用的测试分类及遗留系统的测试策略,对于遗留单体系统,一个可行的思路是先补充中大型的测试,作为基本的冒烟测试,重构优化内部结构后再及时补充中小型测试。同时也给CloudDisk补充了一组基础的大型测试作为冒烟测试,作为后续重构的基本守护测试。
下一篇移动应用遗留系统重构(7)- 解耦重构演示篇(一) 我们将基于方法篇的流程开始对CloudDisk进行重构的改造,具体的解耦操作会以视频的方式展示。
参考资料
CloudDisk示例代码
系列链接
大纲
作者:JunBin
链接:https://juejin.cn/post/6954635678982340622
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。