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

简介:

一个新闻 APP 应该会有以下这些 activity。

  •   语言选择 - 当用户第一次打开软件, 他必须至少选择一种语言。选择后,选项保存在共享偏好中,用户跳转到新闻列表 activity。
  •   新闻列表 - 当用户来到新闻列表 activity,将发送一个包含语言参数的请求到服务器,并将服务器返回的内容显示在 recycler view 上(包含有新闻列表的 id, news_list)。 如果共享偏好中未存语言参数,或者服务器没有返回一个成功消息, 就会弹出一个错误对话框并且 recycler view 将不可见。如果用户只选择了一种语言,新闻列表 activity 有个 “Change your Language” 的按钮,或者如果用户选择多种语言,则按钮为 “Change your Languages” 。 (我对天发誓这是一个虚构的 APP 软件)
  •   新闻细节 - 如同名字所述, 当用户点选新闻列表项时将启动这个 activity。

这个 APP 功能已经足够,,让我们深入研究下为新闻列表 activity 编写的测试用例。 这是我第一次写的代码。

 
  1. /*
  2. Click on the first news item.
  3. It should open NewsDetailActivity
  4. */
  5. @Test
  6. public void testClickOnAnyNewsItem() {
  7. onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
  8. .actionOnItemAtPosition(1, click()));
  9. intended(hasComponent(NewsDetailsActivity.class.getName()));
  10. }
  11. /**
  12. * To test the correct text on the button
  13. */
  14. @Test
  15. public void testChangeLanguageFeature() {
  16. int count = UserPreferenceUtil.getSelectedLanguagesCount();
  17. if (count == 1) {
  18. onView(withText("Choose your Language")).check(matches(isDisplayed()));
  19. } else if (count > 1) {
  20. onView(withText("Choose your Languages")).check(matches(isDisplayed()));
  21. }
  22. ?}

仔细想想测试什么

在第一个测试用例 testClickOnAnyNewsItem(), 如果服务器没有返回成功信息,测试用例将会返回失败,因为 recycler view 是不可见的。但是这个测试用例的目的并非如此。不管该用例为 PASS 还是 FAIL,它的最低要求是 recycler view 总是可见的, 如果因某种原因,recycler view 不可见,那么测试用例不应视为 FAILED。正确的测试代码应该像下面这个样子。

 
  1. /*
  2. Click on any news item.
  3. It should open NewsDetailActivity
  4. */
  5. @Test
  6. public void testClickOnAnyNewsItem() {
  7. try {
  8. /*To test this case, we need to have recyclerView present. If we don't have the
  9. recyclerview present either due to the presence of error_screen, then we should consider
  10. this test case successful. The test case should be unsuccesful only when we click on a
  11. news item and it doesn't open NewsDetail activity
  12. */
  13. ViewInteraction viewInteraction = onView(withId(R.id.news_list));
  14. viewInteraction.check(matches(isDisplayed()));
  15. } catch (NoMatchingViewException e) {
  16. return;
  17. } catch (AssertionFailedError e) {
  18. return;
  19. }
  20.    //在这里我们确信,news_list的 recyclerview 对用户是可见的。
  21.    onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
  22. .actionOnItemAtPosition(1, click()));
  23. intended(hasComponent(NewsDetailsActivity.class.getName()));
  24. }
  25. }

一个测试用例本身应该是完整的

当我开始测试, 我通常按如下顺序测试 activity:

  • 语言选择
  • 新闻列表
  • 新闻细节

因为我首先测试语言选择 activity,在测试 NewsList activity 之前,总有一种语言已经是选择好了的。但是当我先测试新闻列表 activity 时,测试用例开始返回错误信息。原因很简单 - 没有选择语言,recycler view 不会显示。注意, 测试用例的执行顺序不能影响测试结果。 因此在运行测试用例之前, 语言选项必须是保存在共享偏好中的。在本例中,测试用例独立于语言选择 activity 的测试。

 
  1. @Rule
  2. public ActivityTestRule activityTestRule =
  3. new ActivityTestRule(TopicsActivity.class, false, false);
  4. /*
  5. Click on any news item.
  6. It should open NewsDetailActivity
  7. */
  8. @Test
  9. public void testClickOnAnyNewsItem() {
  10. UserPreferenceUtil.saveUserPrimaryLanguage("english");
  11. Intent intent = new Intent();
  12. activityTestRule.launchActivity(intent);
  13. try {
  14. ViewInteraction viewInteraction = onView(withId(R.id.news_list));
  15. viewInteraction.check(matches(isDisplayed()));
  16. } catch (NoMatchingViewException e) {
  17. return;
  18. } catch (AssertionFailedError e) {
  19. return;
  20. }
  21. onView(allOf(withId(R.id.news_list), isDisplayed())).perform(RecyclerViewActions
  22. .actionOnItemAtPosition(1, click()));
  23. intended(hasComponent(NewsDetailsActivity.class.getName()));
  24. ?}

在测试用例中避免使用条件代码

现在在第二个测试用例 testChangeLanguageFeature() 中,我们获取到用户选择语言的个数,基于这个数目,我们写了 if-else 条件来进行测试。 但是 if-else 条件应该写在你的代码当中,而不是测试代码里。每一个条件应该单独测试。 因此,在本例中,不是只写一条测试用例,而是要写如下两个测试用例。

 
  1. /**
  2. * To test the correct text on the button when only one language is selected.
  3. */
  4. @Test
  5. public void testChangeLanguageFeatureForSingeLanguage() {
  6. //Other initializations
  7. UserPreferenceUtil.saveSelectedLanguagesCount(1);
  8. Intent intent = new Intent();
  9. activityTestRule.launchActivity(intent);
  10. onView(withText("Choose your Language")).check(matches(isDisplayed()));
  11. }
  12. /**
  13. * To test the correct text on the button when more than one language is selected.
  14. */
  15. @Test
  16. public void testChangeLanguageFeatureForMultipleLanguages() {
  17. //Other initializations
  18. UserPreferenceUtil.saveSelectedLanguagesCount(5); //Write anything greater than 1.
  19. Intent intent = new Intent();
  20. activityTestRule.launchActivity(intent);
  21. onView(withText("Choose your Languages")).check(matches(isDisplayed()));
  22. }

测试用例应该独立于外部因素

在大多数应用中,我们与外部网络或者数据库进行交互。一个测试用例运行时可以向服务器发送一个请求,并获取成功或失败的返回信息。但是不能因从服务器获取到失败信息,就认为测试用例没有通过。这样想这个问题 - 如果测试用例失败,然后我们修改客户端代码,以便测试用例通过。 但是在本例中, 我们要在客户端进行任何更改吗?- NO

但是你应该也无法完全避免要测试网络请求和响应。由于服务器是一个外部代理,我们可以设想一个场景,发送一些可能导致程序崩溃的错误响应。因此,你写的测试用例应该覆盖所有可能来自服务器的响应,甚至包括服务器决不会发出的响应。这样可以覆盖所有代码,并能保证应用可以处理所有响应,而不会崩溃。

正确的编写测试用例与编写这些测试代码同等重要。

原文发布时间为:2017-02-12

本文来自云栖社区合作伙伴“Linux中国”

相关文章
|
5月前
|
SQL 安全 Java
探索软件测试的多维策略:从单元到集成,再到性能与安全
在软件开发生命周期中,测试是不可或缺的一环。本文将深入探讨软件测试的多维策略,从单元测试、集成测试到性能测试和安全测试等各个层面进行剖析。我们将通过具体的统计数据和案例分析,揭示不同测试策略的优势和应用场景。文章旨在为读者提供一个全面的测试框架,帮助他们构建更稳定、高效和安全的系统。
101 2
|
3月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
211 4
Android性能测试——发现和定位内存泄露和卡顿
|
3月前
|
测试技术 Shell Android开发
Android 性能测试初探 (六)
本节聊聊性能测试的最后一项- 流量,当然我所指的性能测试是针对大部分应用而言的,可能还有部分应用会关注网速、弱网之类的测试,但本系列文章都不去一一探讨了。
59 6
|
3月前
|
JavaScript 测试技术 Android开发
Android 性能测试初探 (四)
本文介绍了GPU在移动端性能测试中的重要性,并详细解释了过度绘制、帧率和帧方差的概念。针对GPU测试,文章列举了三项主要测试内容:界面过度绘制、屏幕滑动帧速率和平滑度。其中,过度绘制测试需遵循特定标准,而帧速率和平滑度测试则可通过软件或硬件方法实现。在软件测试中,使用Systrace插件和高速相机是两种常用手段。对于不同机型,帧率及帧方差的测试标准也需相应调整。
61 5
|
3月前
|
测试技术 Shell Android开发
Android 性能测试初探 (三)
本文承接《Android性能测试初探(二)》,深入探讨CPU与内存测试。介绍了移动端内存测试的重要性及其测试目标,并详细列举了不同状态下应用内存消耗情况的测试项目。此外,还提供了多种内存测试方法,包括使用`procrank`等工具的具体操作步骤。最后,文章也简要提及了CPU测试的相关内容,帮助读者更好地理解Android性能测试的关键要素。
59 5
|
3月前
|
测试技术 Shell 定位技术
Android 性能测试初探 (五)
聊聊大家不常关注的测试项- 功耗
60 3
|
3月前
|
算法 测试技术 Android开发
Android 性能测试初探 (二)
上回大体介绍了下在 android 端的性能测试项,现在我们就细节测试项做一些阐述(包括如何自己 DIY 测试)
51 4
|
3月前
|
测试技术 API Android开发
Android 性能测试初探 (一)
Android 性能测试,跟pc性能测试一样分为客户端及服务器,但在客户端上的性能测试分为 2 类: 一类为 rom 版本的性能测试;一类为应用的性能测试。
55 3
|
3月前
|
Android开发
Android学习 —— 测试init.rc中的条件触发的处理顺序
Android学习 —— 测试init.rc中的条件触发的处理顺序
|
4月前
|
测试技术
探索软件测试的多维视角:从单元到系统,从静态到动态
【8月更文挑战第27天】本文将带领读者穿越软件测试的迷宫,从最微小的单元测试开始,逐步扩展到复杂的系统测试。我们将一起探索静态测试和动态测试的不同面貌,以及它们如何互补地确保软件质量。通过实际代码示例,我们将揭示测试用例的设计思路和执行过程,旨在为读者提供一个全面而深入的软件测试全景图。让我们开始这段旅程,解锁软件测试的秘密,确保我们的代码不仅能够运行,而且能够完美运行。
下一篇
DataWorks