目录
前言
随着当今社会竞争压力的增加,应用版本的迭代也越来越频繁,那么测试就显得举足轻重了,可是每次发一个版本全面测试的话非常消耗人力资源, 不全面测试的话可能存在bug。这是一个两难的问题。然而在写项目代码的同时加上对应的测试代码就能很好的避免这个问题。这也是TO-DO demo吸引我的又一亮点。
测试代码
基于上一篇的基础上来说说demo中的测试代码,这篇demo中测试代码写的也比较全面,包含了UI测试,和业务操作的测试。
UI测试
以AppNavigationTest为例
// 省略导入的包
@RunWith(AndroidJUnit4.class)
@LargeTest
public class AppNavigationTest {
@Rule
public ActivityTestRule<TasksActivity> mActivityTestRule =
new ActivityTestRule<>(TasksActivity.class);
//...具体的测试用例
}
这是一个没有任何测试任务的单元测试类
@RunWith(AndroidJUnit4.class),表示是以AndroidJUnit4为单元测试
@LargeTest,测试规模限定符。表示在当前类中能进行大型的单元测试
@Rule,为单元测试限定测试所在的范围(代码中测试范围为TaskActivity)
接下来以一个单元测试为例来看看UI测试的代码该怎么写
@Test
public void clickOnStatisticsNavigationItem_ShowsStatisticsScreen() {
openStatisticsScreen();
// 3.检测统计页面是否处于活动状态(此时检测的是统计页面中的某个组件是否处于活动状态)
onView(withId(R.id.statistics)).check(matches(isDisplayed()));
}
private void openStatisticsScreen() {
// 1.获取左侧滑栏的所在的视图并去检查为关闭状态,并打开左侧滑栏
onView(withId(R.id.drawer_layout)).check(matches(isClosed(Gravity.LEFT)))
.perform(open());
// 2.获取左侧滑栏视图,并模拟点击R.id.statistics_navigation_menu_tetem,使页面跳转
onView(withId(R.id.nav_view))
.perform(navigateTo(R.id.statistics_navigation_menu_tetem));
}
这是打开统计页面的单元测试,以注释的形式说明测试流程。不难看出单元测试是有着很严格思维逻辑
操作测试
相比UI测试,业务逻辑的操作测试会更复杂一点。以TasksScreenTest为例,来看看从增加task到操作task的一套流程。
// ... 省略包
@RunWith(AndroidJUnit4.class)
@LargeTest
public class TasksScreenTest{
@Rule
public ActivityTestRule<TasksActivity> mTasksActivityTestRule =
new ActivityTestRule<TasksActivity>(TasksActivity.class){
// activity启动前执行的方法(可用来释放资源)
@Override
protected void beforeActivityLaunched() {
super.beforeActivityLaunched();
// activity启动前删除所有的任务列表
Injection
.provideTasksRepository(InstrumentationRegistry.getTargetContext())
.deleteAllTasks();
}
}
}
这也是一个没有任何单元测试任务的测试类, 相比上面的多了一个启动前执行的操作。接下来我将以增加、编辑task到操作task为例来看看业务操作测试的流程
// step1.addTask
private void createTask(String title, String description){
// 进入add task的页面
onView(withId(R.id.fab_add_task)).perform(click());
// 增加title、description
onView(withId(R.id.add_task_title)).perform(typeText(title), closeSoftKeyboard());
onView(withId(R.id.add_task_description)).perform(typeText(description),
closeSoftKeyboard());
// 保存task
onView(withId(R.id.fab_edit_task_done)).perform(click());
}
// step2.editTask
@Test
public void editTask() throws Exception {
// step1.addTask
createTask("title1", "description1");
// 选中task
onView(withId(R.id.fab_edit_task)).perform(click());
// 修改title、description
onView(withId(R.id.add_task_title)).perform(typeText("title2"), closeSoftKeyboard());
onView(withId(R.id.add_task_description)).perform(typeText("description2"),
closeSoftKeyboard());
// 保存task
onView(withId(R.id.fab_edit_task_done)).perform(click());
// 校验修改后的task是否在修改列表
onView(withItemText("title2")).check(matches(isDisplayed()));
// 校验修改前的task是否不存在列表
onView(withItemText("title1")).check(doesNotExist());
}
对比这些单元测试我们能发现如下的规律:
1.单元测试非常灵活,可以单一操作的测试,也可以组合操作的测试。
2.单元测试代码具有很强的规范性,做到了见方法名知道功能
3.熟悉单元测试的写法后,单元测试还是很简单的
注:有一点需要说明的是每个@Test注解下的方法是相互独立的,譬如在上一个@Test方法中打开了A 界面,在下一个@Test方法中需要使用到A界面则需要再次打开A界面,否则测试失败