编写Android测试单元该做的和不该做的事

在本文中, 我将根据我的实际经验,为大家阐述一个编写测试用例的最佳实践。在本文中我将使用 Espresso 编码, 但是它们可以用到单元测试和仪器测试(instrumentation test)当中。基于以上目的,我们来研究一个新闻程序。

以下内容纯属虚构,如有雷同纯属巧合 :P
一个新闻 APP 应该会有以下这些 activity。
语言选择 - 当用户第一次打开软件, 他必须至少选择一种语言。选择后,选项保存在共享偏好中,用户跳转到新闻列表 activity。
新闻列表 - 当用户来到新闻列表 activity,将发送一个包含语言参数的请求到服务器,并将服务器返回的内容显示在 recycler view 上(包含有新闻列表的 id, news_list)。 如果共享偏好中未存语言参数,或者服务器没有返回一个成功消息, 就会弹出一个错误对话框并且 recycler view 将不可见。如果用户只选择了一种语言,新闻列表 activity 有个 “Change your Language” 的按钮,或者如果用户选择多种语言,则按钮为 “Change your Languages” 。 (我对天发誓这是一个虚构的 APP 软件)
新闻细节 - 如同名字所述, 当用户点选新闻列表项时将启动这个 activity。
这个 APP 功能已经足够,,让我们深入研究下为新闻列表 activity 编写的测试用例。 这是我第一次写的代码。
/*
Click on the first news item.
It should open NewsDetailActivity
/
@Test
public void testClickOnAnyNewsItem() {
onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
.actionOnItemAtPosition(1, click()));
intended(hasComponent(NewsDetailsActivity.class.getName()));
}
/
*

  • To test the correct text on the button
    /
    @Test
    public void testChangeLanguageFeature() {
    int count = UserPreferenceUtil.getSelectedLanguagesCount();
    if (count == 1) {
    onView(withText("Choose your Language")).check(matches(isDisplayed()));
    } else if (count > 1) {
    onView(withText("Choose your Languages")).check(matches(isDisplayed()));
    }
    ?}
    仔细想想测试什么
    在第一个测试用例 testClickOnAnyNewsItem(), 如果服务器没有返回成功信息,测试用例将会返回失败,因为 recycler view 是不可见的。但是这个测试用例的目的并非如此。 不管该用例为 PASS 还是 FAIL,它的最低要求是 recycler view 总是可见的, 如果因某种原因,recycler view 不可见,那么测试用例不应视为 FAILED。正确的测试代码应该像下面这个样子。
    /

    Click on any news item.
    It should open NewsDetailActivity
    /
    @Test
    public void testClickOnAnyNewsItem() {
    try {
    /*To test this case, we need to have recyclerView present. If we don't have the
    recyclerview present either due to the presence of error_screen, then we should consider
    this test case successful. The test case should be unsuccesful only when we click on a
    news item and it doesn't open NewsDetail activity
    */
    ViewInteraction viewInteraction = onView(withId(R.id.news_list));
    viewInteraction.check(matches(isDisplayed()));
    } catch (NoMatchingViewException e) {
    return;
    } catch (AssertionFailedError e) {
    return;
    }
       //在这里我们确信,news_list的 recyclerview 对用户是可见的。
       onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
    .actionOnItemAtPosition(1, click()));
    intended(hasComponent(NewsDetailsActivity.class.getName()));
    }
    }
    一个测试用例本身应该是完整的
    当我开始测试, 我通常按如下顺序测试 activity:
    语言选择
    新闻列表
    新闻细节
    因为我首先测试语言选择 activity,在测试 NewsList activity 之前,总有一种语言已经是选择好了的。但是当我先测试新闻列表 activity 时,测试用例开始返回错误信息。原因很简单 - 没有选择语言,recycler view 不会显示。注意, 测试用例的执行顺序不能影响测试结果。 因此在运行测试用例之前, 语言选项必须是保存在共享偏好中的。在本例中,测试用例独立于语言选择 activity 的测试。
    @Rule
    public ActivityTestRule activityTestRule =
    new ActivityTestRule(TopicsActivity.class, false, false);
    /

    Click on any news item.
    It should open NewsDetailActivity
    /
    @Test
    public void testClickOnAnyNewsItem() {
    UserPreferenceUtil.saveUserPrimaryLanguage("english");
    Intent intent = new Intent();
    activityTestRule.launchActivity(intent);
    try {
    ViewInteraction viewInteraction = onView(withId(R.id.news_list));
    viewInteraction.check(matches(isDisplayed()));
    } catch (NoMatchingViewException e) {
    return;
    } catch (AssertionFailedError e) {
    return;
    }
    onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
    .actionOnItemAtPosition(1, click()));
    intended(hasComponent(NewsDetailsActivity.class.getName()));
    ?}
    在测试用例中避免使用条件代码
    现在在第二个测试用例 testChangeLanguageFeature() 中,我们获取到用户选择语言的个数,基于这个数目,我们写了 if-else 条件来进行测试。 但是 if-else 条件应该写在你的代码当中,而不是测试代码里。每一个条件应该单独测试。 因此,在本例中,不是只写一条测试用例,而是要写如下两个测试用例。
    /
    *
  • To test the correct text on the button when only one language is selected.
    /
    @Test
    public void testChangeLanguageFeatureForSingeLanguage() {
    //Other initializations
    UserPreferenceUtil.saveSelectedLanguagesCount(1);
    Intent intent = new Intent();
    activityTestRule.launchActivity(intent);
    onView(withText("Choose your Language")).check(matches(isDisplayed()));
    }
    /
    *
  • To test the correct text on the button when more than one language is selected.
    */
    @Test
    public void testChangeLanguageFeatureForMultipleLanguages() {
    //Other initializations
    UserPreferenceUtil.saveSelectedLanguagesCount(5); //Write anything greater than 1.
    Intent intent = new Intent();
    activityTestRule.launchActivity(intent);
    onView(withText("Choose your Languages")).check(matches(isDisplayed()));
    }
    测试用例应该独立于外部因素
    在大多数应用中,我们与外部网络或者数据库进行交互。一个测试用例运行时可以向服务器发送一个请求,并获取成功或失败的返回信息。但是不能因从服务器获取到失败信息,就认为测试用例没有通过。这样想这个问题 - 如果测试用例失败,然后我们修改客户端代码,以便测试用例通过。 但是在本例中, 我们要在客户端进行任何更改吗?- NO。
    但是你应该也无法完全避免要测试网络请求和响应。由于服务器是一个外部代理,我们可以设想一个场景,发送一些可能导致程序崩溃的错误响应。因此,你写的测试用例应该覆盖所有可能来自服务器的响应,甚至包括服务器决不会发出的响应。这样可以覆盖所有代码,并能保证应用可以处理所有响应,而不会崩溃。
    正确的编写测试用例与编写这些测试代码同等重要。
    感谢你阅读此文章。希望对测试用例写的更好有所帮助。你可以在 LinkedIn 上联系我。还可以在这里阅读我的其他文章。
    获取更多资讯请关注我们, 我们发新文章时您将获得通知。

作者:Anshul Jain
来源:51CTO

时间: 2024-12-28 02:37:52

编写Android测试单元该做的和不该做的事的相关文章

编写 android 测试单元该做的和不该做的事

一个新闻 APP 应该会有以下这些 activity.   语言选择 - 当用户第一次打开软件, 他必须至少选择一种语言.选择后,选项保存在共享偏好中,用户跳转到新闻列表 activity.   新闻列表 - 当用户来到新闻列表 activity,将发送一个包含语言参数的请求到服务器,并将服务器返回的内容显示在 recycler view 上(包含有新闻列表的 id, news_list). 如果共享偏好中未存语言参数,或者服务器没有返回一个成功消息, 就会弹出一个错误对话框并且 recycle

世界级的Android测试开发流程(二)

本文讲的是世界级的Android测试开发流程(二), 在我们的上一篇博客文章,"世界级的Android测试开发流程(一)",我们开始讨论一个Android的测试开发流程.我们讨论了一个软件工程师从开始写测试到找到测试开发的一些问题的演化过程.我们获得了以下结论,概括如下: 自动化测试是成功的软件开发的关键. 为了写特定类型的测试,可测试的代码是必须的. 一些开发者对测什么与怎么测一无所知,就开始写测试. 我们的测试的质量与可读性并不总是能达到预期. 一个测试开发流程对定义测什么与怎么测

使用MVVM编写可测试的表示层

在使用 Windows 窗体时代的传统应用程序的情况下,标准测试做法是布局一个视图,在该视图的代 码隐藏文件中编写代码,然后运行该应用程序以进行测试.幸运的是,在那以后,相关做法有了一些变 化. Windows Presentation Foundation (WPF) 的出现将数据绑定概念提升到了一个全新的水平.它使得 一种称为"模型-视图-视图模型"(MVVM) 的新设计模式得到发展.通过 MVVM,您可以将表 示逻辑与实际表示分离开.基本上,这意味着您可以在极大程度上避免在视图的

2014非常好用的开源Android测试工具

当前有很大的趋势是转向移动应用平台,Android 是最广泛使用的移动操作系统,2014 年大约占 80% 以上的市场.在开发 Android 应用的时候要进行测试,现在市场上有大量的测试工具. 本文主要是展示一系列的开源 Android 测试工具.每个工具都会有相应的简短介绍,还有一些相关的资源.Android 测试工具列表是按照字母来排序的,最后还会介绍几个不是特别活跃的 Android 测试相关的开源项目. 本文提到的开源 Android 软件测试工具包括:Android Test Kit

Android 测试入门篇_Android

Android构架 1. Application 应用程序层:用Java语言编写的运行在虚拟机的程序 用户直接使用的功能,其基本应用比如:电话.联系人.短信.邮件等,还有无数第三方应用. 2. Application Framework 应用架构层:编写Google发布的核心应用程序的API框架 开发应用程序使用的基础组件,相当于供应用程序调用的API.Java开发,包括:丰富的界面控件.Content Provider,数据存储组件,应用程序可以通过Content Provider分项数据给其

Android测试教程

一.  测试项目    Android的编译和测试工具需要测试项目组织符合预订的结构:分别为Test case 类,Test case 包以及测试项目. JUnit 为Android的测试的基础,一般来说,一个JUint测试为一个用来测试一个应用某一部分的语句. 你可以将多个测试Test方法组织起来构成一个测试用例(Test case),多个测试用例可以构成Test Suites . 每个Test方法相对独立,一个测试类Test class包含一组相关的Test 或其它辅助方法. 在Androi

用PHP编写Android应用程序

Google的开源Android移动操作系统正在席卷全球智能手机市场,和苹果不一样,它对那些想将应用程序提交到iPhone App Store的开发人员有着严格的指导方针和要求,Google的Android平台非常开放,甚至还可以用PHP编写Android应用程序,Irontech创建了一个运行在Android上的PHP移植程序,结合Android的脚本层(Scripting Layer for Android,SL4A),你就可以构建PHP Android应用程序了. 在这篇文章中,我们将介绍

Android 测试入门篇

Android构架 1. Application 应用程序层:用Java语言编写的运行在虚拟机的程序 用户直接使用的功能,其基本应用比如:电话.联系人.短信.邮件等,还有无数第三方应用. 2. Application Framework 应用架构层:编写Google发布的核心应用程序的API框架 开发应用程序使用的基础组件,相当于供应用程序调用的API.Java开发,包括:丰富的界面控件.Content Provider,数据存储组件,应用程序可以通过Content Provider分项数据给其

Android测试教程(17):Monkey 命令行工具

写完应用之后,作完单元测试和功能测试,有必要对应用的抗打击能力做个测试,最好的方法是雇个"猴子"在测试,猴子 可以胡乱瞎按键,在这种情况下,你的应用是否还能正常工作呢? Android 测试包中提供了一个Monkey工具,就提供了"猴 子"功能,不过比真"猴子"还要智能一些,你还可以指挥这个猴子, 比如按键的比例,触发某个事件的频率等等. 一 个简单的用法,比如你的应用程序的包名为:com.pstreets.navigator 可以使用  adb