精通移动App测试实战:技术、工具和案例

978-7-115-41707-7
作者: 于涌 王磊 曹向志
译者:
编辑: 张涛

图书目录:

详情

本书从Android系统的介绍、移动开发环境的部署、移动应用的开发、ADB相关命令的应用、Junit单元测试工具的应用、基于Android系统稳定性测试工具Monkey的应用、移动平台自动化测试Uiautomator、Robotium自动化测试工具应用、基于Android平台性能测试等多方面理论联系实践进行了介绍。

图书摘要

版权信息

书名:精通移动App测试实战:技术、工具和案例

ISBN:978-7-115-41707-7

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 编  著  于  涌  王  磊  曹向志

  责任编辑 张 涛

• 人民邮电出版社出版发行    北京市丰台区成寿寺路11号

  邮编 100164    电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

•  读者服务热线:(010)81055410

  反盗版热线:(010)81055315


于涌,毕业于北京大学计算机系,先后担高级程序员、测试分析师、高级测试经理等职位。拥有二十年丰富的开发、测试及管理经验。现致力于软件测试理论和实践研究,尤其擅长自动化测试工具应用、性能测试和单元测试等。曾为多个大型软件公司、高校企事业和专业培训机构提供软件测试、性能测试、安全测试、移动测试、自动化测试等理论和相关工具应用方面的咨询、培训和实施指导工作,具有丰富的实践和教学经验。多本软件测试畅销书的作者。

本书特色

业界知名的测试专家,多本畅销书作者

Monkey、MonkeyRunner、Robotium、uiautomator、Appium

操作系统、系统调试、自动化脚本开发、测试用例批量执行、持续集成

LoadRunner在移动端性能测试的应用


本书全面讲解了移动平台测试方面的技术、技巧、工具和测试用例等实战知识。内容涵盖主流的测试工具,包括JUnit、Monkey、MonkeyRunner、Robotium、UIAutomator、Appium,以及性能测试利器LoadRunner、手机端性能监控工具Emmagee等;重点讲解移动平台的主要实战技术,如单元测试、功能测试、性能测试、UI测试、手游测试、自动化测试、测试用例管理、持续集成、脚本录制等。书中结合实例对各个工具进行深入讲解,真正做到学以致用。本书既是一本真正帮助读者学习移动测试中用到的所有技术的实战教程,也是一本名副其实的、贴近实战的移动端测试权威指南。

本书适合测试初学者、测试工程师、测试经理、移动开发人员和游戏开发人员学习借鉴,也可以作为大专院校相关专业师生和培训学校的教学用书。


本书是测试专家、畅销书作者多年实战经验的总结,涵盖主流的测试工具,包括众多的测试实例,涵盖单元测试、功能测试、性能测试、UI测试、手游测试、自动化测试、测试用例管理、持续集成等移动测试中用到的所有实战技术,是一本贴近实战的移动端测试参考大全。本书主要内容如下。

书中讲解了单元测试,介绍了JUnit框架、单元测试实施、创建基于Android的测试项目和应用JUnit对Android项目进行单元测试;讲解了Android 提供的一个通用的调试工具ADB,借助这个工具,可以很好地调试开发的程序,包括ADB相关指令实例讲解、获取手机处理器信息指令实例讲解、手机模拟器相关的一些操作命令实例讲解、模拟器相关命令实例讲解、创建Android项目相关命令实例讲解、基于控制台命令行相关命令使用;讲解了Android系统自带的一个命令行工具Monkey,Monkey可以向被测试的应用程序发送伪随机的用户事件(如按键、触屏、手势等),Monkey测试是一种测试软件稳定性、健壮性的快速有效的方法。包括Monkey工具使用、Monkey测试示例、Monkey相关参数讲解、Monkey相关命令介绍、Monkey脚本执行等;结合实例讲解了由Google开发、用于Android系统自动化测试的MonkeyRunner工具,包括MonkeyRunner工具使用、MonkeyRunner测试示例、MonkeyRunner脚本手工编写、MonkeyRunner样例脚本等;书中还讲解了一款Android自动化测试框架Robotium,它主要针对Android平台的应用进行黑盒自动化测试,提供了模拟各种手势操作(如点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。用Robotium结合Android官方提供的测试框架可以达到对应用程序进行自动化测试的目的,如用Robotium实现对APK或有源码的项目实施测试、用Robotium Recorder 录制脚本、用Robotium获取控件,以及测试用例脚本的批量运行和持续集成等;讲解了UI测试工具UIAutomator,它包含了创建UI测试的各种API和执行自动化测试的引擎;UIAutomator接口丰富、易用,可以支持所有Android事件操作,非常适合做UI测试;Appium 是一个自动化测试开源工具,支持 iOS 和 Android平台上的移动原生应用、移动Web应用和混合应用测试;Appium 是一个跨平台的工具,它允许测试人员使用同样的接口基于不同的平台(iOS、Android)编写自动化测试脚本,这样大大增加了 iOS 和 Android 测试用例的复用性,还讲解了自动化测试工具Appium实战、Appium环境部署、Appium元素定位的3个利器、多种界面控件的定位方法、多种界面控件的操作方法、捕获异常和创建快照等;书中最后结合案例讲解了移动平台的性能测试,性能测试的8大分类,移动端的性能指标,移动端性能测试工具,如手机端的性能监控工具Emmagee、LoadRunner在移动端性能测试中的应用等。TraceView 是 Android 平台自带的一个很好用的性能分析工具,它可以通过图形化的方式让我们了解要跟踪的应用程序的性能;Systrace 是 Android 4.1(API:16)以后引入的一个用于做性能分析的工具,该工具可以定时收集和监测Android设备的相关信息,它显示了每个线程或者进程在给定的时间里占用CPU的情况;Emmagee是网易杭州研究院QA团队开发的一个简单易用的Android性能监测工具,主要用于监控单个手机应用的CPU、内存、流量、启动耗时、电量、电流等性能状态的变化,且用户可以自定义配置监控的采样频率及性能的实时显示,并最终生成一份性能统计文件;LoadRunner的最新版本为LoadRunner 12.0,结合目前移动市场性能测试的需要,LoadRunner 也提供了一些基于移动平台的协议和相应的工具,本书中都会有讲解。

写作过程中,作者倾尽全力,由于时间紧,加之水平有限,书中错误在所难免,诚请广大读者给予指正,以便再版时修正完善,本书答疑QQ群为191026652,本书编辑联系邮箱为zhangtao@ptpress.com.cn。

本书适合测试初学者、测试工程师、测试经理、移动开发人员和游戏开发人员学习使用,也可以作为大专院校相关专业师生和培训学校的教学用书。


工欲善其事必先利其器,因为本书主要是针对移动平台讲解测试方面的内容,所以对移动平台目前主流的Android系统有一个了解十分必要,下面我们就一起来了解一下这个操作系统相关的知识内容。

Android一词的原意指“机器人”,同时也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成。

Android的Logo是由Ascender公司设计的,诞生于2010年,其设计灵感源于男女厕所门上的图形符号。布洛克绘制了一个简单的机器人,它的躯干就像锡罐的形状,头上还有两根天线,Android小机器人便诞生了。

从图1-1中我们不难发现Android的系统架构采用了分层的架构,分为4个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和Linux内核层。那么它们每层都是用来做什么的呢?

1.应用程序层

应用层是用Java语言编写的运行在Android平台上的程序,比如一些手机游戏和基于手机端的应用等,如图1-1所示,最上面的Applications层。

图1-1 Android系统架构图

2.应用程序框架层

应用程序框架层是编写Google发布的核心应用时所使用的API框架,开发人员可以使用这些框架来开发自己的应用程序,这样可以简化程序开发的架构设计,如图1-1所示,第二层,即Application Framework层,其提供的主要API框架如下。

活动管理器:主要用来管理应用程序声明周期,并提供常用的导航退回功能。

窗口管理器:主要用来管理所有的窗口程序。

内容提供器:它可以让一个应用访问另一个应用的数据,或共享它们自己的数据。

视图管理器:主要用来构建应用程序,比如列表、表格、文本框及按钮等。

通知管理器:主要用来设置在状态栏中显示的提示信息。

包管理器:主要用来对Android系统内的程序进行管理。

电话管理器:主要用来对联系人及通话记录等信息进行管理。

资源管理器:主要用来提供非代码资源的访问,例如本地字符串、图形及布局文件等。

位置管理器:主要用来提供使用者的当前位置等信息,如GPRS定位。

XMPP Service:XMPP服务。

3.系统运行库层

系统运行库层主要提供Android程序运行时需要的一些类库,这些类库一般是使用C/C++语言编写的。另外,该层还包含了Android运行库。如图1-1所示,第三层,系统运行库层中包含的主要库如下。

libc:C语言标准库,系统最底层的库,C语言标准库通过Linux系统来调用。

Surface Manager:主要管理多个应用程序同时执行时各个程序之间的显示与存取,并且为多个应用程序提供2D和3D图层的无缝融合。

SQLite:关系数据库。

OpenGL|ES:3D效果的支持。

Media Framework:Android系统多媒体库,该库支持多种常见格式的音频、视频的回放和录制。

WebKit:Web浏览器引擎。

SGL:2D图形引擎库。

SSL:位于TCP/IP协议与各种应用层协议之间,为数据通信提供支持。

FreeType:位图及矢量库。

系统运行库层中还包含了一个Dalvik虚拟机,相对于桌面系统和服务器系统运行的虚拟机而言,它不需要很快的CPU计算速度和大量的内存空间。因此,它非常适合在移动终端上使用。

4.系统内核层

Android的核心系统服务基于Linux 2.6内核,该内核拥有安全性、内存管理、进程管理、网络协议栈和驱动模型等。同时它也作为硬件和软件栈之间的抽象层,而Android更多的是需要一些与移动设备相关的驱动程序,比如显示驱动、USB接口驱动、蓝牙驱动、电源驱动、Wi-Fi驱动等,如图1-1所示,最下面即为该层。

Android操作系统其实是一个多用户的Linux操作系统,每个Android应用都使用不同的用户,运行在自己的安全沙盘里。系统为应用的所有文件设置权限,这样一来只有同一个用户的应用可以访问它们。每个应用都有自己单独的虚拟机,这样应用的代码在运行时是隔离的,即一个应用的代码不能访问或意外修改其他应用的内部数据。

每个应用都运行在单独的Linux进程中,当应用被执行时,Android都会为其启动一个Java虚拟机,因此不同的应用运行在相互隔离的环境中。Android系统采用最小权限原则确保系统的安全性。也就是说,每个应用默认只能访问满足其工作所需的功能,而不能访问其无权使用的功能。那么我们要实现移动平台的自动化测试时,比如应用Robotium,就涉及到它和被测试应用的交互,如果是上面的机制是不是意味着我们没有办法实施自动化测试呢?当然能够解决该类问题,不同的应用可以运行在相同的进程中,要实现这个功能,就必须保证应用使用相同的密钥签名、在AndroidManifest.xml文件中为这些应用分配相同的Linux用户ID。同时,如果应用需要用到照相、Wi-Fi、蓝牙、SD卡的读写操作等都需要进行授权。

Activity(活动):我们在后续的图书内容阅读过程中经常会看到这个词,那么什么是活动呢,就像我们在操作一些应用软件,比如Word,它出现的每一个功能界面,比如在编辑文件、改变字体大小后,我们单击工具条的“保存”按钮;或者是一个拼车的手机应用,我们约车的时候,其也会提供一个界面,需要我们指定出发的地点、目的地、出发时间等信息,单击“确认预约”按钮。它们都是软件系统和我们用户的一个交互,这个和我们交互的界面就叫一个“活动”。

Service(后台服务):后台服务通常没有交互的图形界面,是多用于处理长时间任务,而不影响前台用户体验的组件。如我们一边看着“微信”应用的朋友圈内容,一边欣赏着手机的音乐,怡然自得的时候是否知道其有一个后台播放音乐的服务呢?

Content Provider(内容供应组件):内容供应组件用来管理应用的可共享部分的数据。例如,应用将数据存储在文件系统或者SQLite数据库中,通过内容供应组件,其他的应用也可以对这些数据进行查询。例如,我们手机自带联系人信息,其他的应用只要有相应的权限就可以通过查询内容供应组件来查询该联系人的相关信息。

Broadcast Receivers(广播接收组件):在 Android 里面有各种各样的广播,电池的使用状态、电话的接收和短信的接收等都会产生一个广播,应用程序开发者也可以监听这些广播并做出程序逻辑的处理。

基于移动平台的自动化测试,通常都需要我们有一定的语言基础、单元测试基础和IDE(Integrated Development Environment,集成开发环境)。软件是用于程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面工具。它是集成了代码编写、编译、调试和分析等一体化的辅助开发人员开发软件的应用软件,目前应用比较广泛的IDE有VisualStudio、Eclipse等。

根据工作环境和个人喜好不同,既可以在Windows系统环境下部署Android开发环境,也可以在Linux系统环境下部署Android开发环境,关于这方面的资料在互联网上可大量查询。鉴于目前大多数测试人员应用Windows系统,这里主要以Windows 7系统环境为例,向大家讲解如何在Windows 7 64位系统环境下搭建Android开发环境。

Android应用程序开发使用Java语言,所以我们首先要搭建Java程序开发运行环境。Java的开发环境称为JDK(Java Development Kit),是Sun Microsystems针对Java应用开发人员开发的产品,JDK已经成为使用最广泛的Java SDK(Software Development Kit,软件开发工具包)。

可以访问“http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html”这个地址来下载最新的JDK,如图1-2所示。

图1-2 JDK下载界面信息

从图1-2中我们可以看到Oracle 提供了基于不同操作系统的JDK包,这里因为我们应用的是Windows 7 64位的操作系统,所以要下载图1-2所示的“jdk-8u45-windows-x64.exe”文件。

接下来双击“jdk-8u45-windows-x64.exe”文件,将出现图1-3所示界面。

图1-3 JDK安装向导-安装程序

单击“下一步”按钮,将出现图1-4所示界面。

图1-4 JDK安装向导-定制安装

单击“下一步”按钮,将出现图1-5所示界面,这里我们选择其默认的安装目录,不做改变。

图1-5 JDK安装向导-目标文件夹

单击“下一步”按钮,将出现图1-6所示界面,开始安装JDK的相关文件。

图1-6 JDK安装向导-进度

待相关文件安装完成后,将出现图1-7所示界面,表示JDK已安装到Windows 7操作系统,单击“关闭”按钮。

图1-7 JDK安装向导-完成

接下来,开始配置Windows系统相关环境变量,鼠标右键单击桌面的“计算机”图标,在弹出的快捷菜单中选择“属性”菜单项,将弹出图1-8所示对话框,单击“环境变量”按钮。

图1-8 系统属性对话框

单击弹出的“环境变量”对话框中“系统变量”下的“新建”按钮,如图1-9所示。在弹出的图1-10所示对话框中新建一个系统环境变量,其变量名为“JAVA_HOME”,因为我们将JDK安装在“C:\Program Files\Java\jdk1.8.0_45”,所以对应的变量值为“C:\Program Files\Java\jdk1.8.0_45”。

图1-9 环境变量对话框

图1-10 新建系统变量对话框

在系统变量列表中找到“Path”变量,在变量值最后加入运行Java应用中的一些可执行文件所在的路径“;C:\Program Files\Java\jdk1.8.0_45\bin”,如图1-11所示。

图1-11 编辑Path环境变量

再新建一个名称为“CLASSPATH”的系统环境变量,变量值为“.;%JAVA_HOME%\lib\ tools.jar;%JAVA_HOME%\lib\dt.jar”,相关的详细配置信息如图1-12所示。

图1-12 编辑CLASSPATH环境变量

最后,验证JDK安装、设置是否成功,在控制台命令行下输入“java -version”,若出现图1-13所示信息,则表示安装、部署成功。

图1-13 命令行控制台下运行“java -version”的显示信息

Android SDK是Google提供的Android开发工具包,在我们开发Android 应用的时候,需要通过引入其工具包来使用Aandroid相关的API。

通过访问" http://developer.android.com/sdk/index.html”下载Android SDK,如图1-14所示。

图1-14 Android SDK不同系统版本下载地址

这里,我们下载其推荐的版本,单击“installer_r24.2-windows.exe”链接进行下载。选中接下来弹出的图1-15所示界面的“I have read and agree with the above terms and conditions”复选框,单击“Download installer_r24.2-windows.exe”按钮。

图1-15 “Download installer_r24.2-windows.exe”的显示信息

文件“installer_r24.2-windows.exe”下载完成后,运行该文件,弹出图1-16所示界面,单击“Next”按钮。

图1-16 “Android SDK Tools Setup”对话框信息

在后续安装路径中,我们选择安装到“E:\android-sdk”,如图1-17所示。

图1-17 “Android SDK Tools Setup-Choose Install Location”对话框信息

安装完成后,在弹出的图1-18所示对话框中单击“Finish”按钮,启动“Android SDK Manager”应用,如图1-19所示。

图1-18 “Android SDK”安装完成后对话框

在弹出的“Android SDK Manager”应用对话框中,我们可以选择需要安装的API版本和相应的工具包相关信息,然后单击“Install 40 packages”按钮,如图1-19所示。

图1-19 “Android SDK Manager”对话框信息

在弹出的图1-20所示对话框中,选择“Accept”和“Accept License”单选按钮,单击“Install”安装已选择的内容。

图1-20 “Choose Packages to Install”对话框信息

在安装过程中,将显示安装进度、下载速度等相关信息,如图1-21所示。当然,我们选择的内容越多,相应的安装时间也就越长。

图1-21 下载进度相关信息

通过访问“http://www.eclipse.org/downloads/?osType=win32”下载Eclipse,如图1-22所示。

图1-22 Eclipse的Windows 版本下载地址

这里选择下载其64位的版本,单击“Windows 64 Bit”链接,将弹出图1-23所示界面。单击方框所示下载“eclipse-java-luna-SR2-win32-x86_64.zip”文件。

图1-23 Eclipse的Windows 版本下载镜像相关信息

“eclipse-java-luna-SR2-win32-x86_64.zip”文件下载完成以后,用WinRAR等工具打开它,将其包含的“eclipse”文件夹进行解压,如图1-24所示。这里,我们将其解压到“E:”根目录下。

图1-24 “eclipse-java-luna-SR2-win32-x86_64.zip”压缩包相关信息

Android ADT的全称是Android Development Tools,它是Google提供的一个Eclipse插件,用于在Eclipse中提供强大的、高度集成的Android开发环境。在Eclipse中并不能直接开发Android程序,需要安装ADT插件,下面我们就来讲解如何安装ADT插件。

首先,打开Eclipse,单击“Help>Install New Software”菜单项,显示图1-25所示对话框信息。

图1-25 “Install”对话框信息

单击图1-25所示对话框右侧的“Add”按钮,在弹出的图1-26所示对话框中Name栏输入“ADT”,Location栏输入“http://dl-ssl.google.com/android/eclipse/”,单击“OK”按钮,对其进行保存。

图1-26 “Add Repository”对话框信息

稍等片刻后,将出现图1-27所示界面信息,我们可以从图1-27所示的“Developer Tools”下的选项中选择要安装的选项,然后单击“Next”按钮。

图1-27 “Install”对话框信息

在弹出的图1-28所示对话框中,单击“Next”按钮。

图1-28 “Install-Install Details”对话框信息

在弹出的图1-29所示对话框中,单击选择“I accept the terms of the license agreements”,然后单击“Finish”按钮。

图1-29 “Install-Review Licenses”对话框信息

这里需要提醒的是Android SDK和ADT相关包下载过程比较耗时,大家还需要有耐心。

接下来,开始配置ADT相关内容,启动Eclipse,单击“Windows>Preferences”菜单项,显示图1-30所示对话框。单击“Android”页,在SDK Location中输入或者单击“Browse”按钮选择“E:\android-sdk”(也就是我们Android SDK安装位置文件夹)。单击“OK”按钮对上述设置进行保存。

图1-30 “Preferences”对话框信息

上面章节我们详细讲解了Windows 7系统环境下Android开发环境的搭建过程,是不是觉得很复杂?

其实,还可以在“http://developer.android.com/sdk/index.html”下载一些其他基于Android 应用开发的工具,如目前比较受大家关注的“Android Studio”,如图1-31所示。

图1-31 “Android Studio”下载相关信息

在我们日常进行自动化测试脚本开发时,会经常调试测试脚本,既可以在实际的物理手机设备上进行调试,也可以通过创建一个或者多个手机设备模拟器来进行调试。

创建模拟器的方法有很多,既可以通过Eclipse的工具条按钮创建,也可以直接启动AVD Manager创建,还可以通过命令创建,这几种方式都可以。

如图1-32所示,单击Eclipse工具条的“手机”图标或者选中“Window >Android Virtual Device Manager”菜单项,也可以直接双击Android SDK目录下的“AVD Manager.exe”文件,都能启动“Android Virtual Device(AVD)Manager”应用,如图1-33所示。

图1-32 Eclipse工具条相关信息

图1-33 “Android Virtual Device(AVD)Manager”应用界面信息

单击“Create…”按钮,将弹出图1-34所示对话框。

图1-34 “Create new Android Virtual Device(AVD)”对话框信息

这里,我们要创建一个名称为“Galaxy_Nexus_4.4.2”的安卓虚拟设备,依次在对应的界面输入或者选择如下信息,如图1-35所示。

图1-35 “Galaxy_Nexus_4.4.2”模拟器相关配置信息

下面对图1-35所示的相关信息项进行讲解。“AVD Name”表示安卓虚拟设备名称,也就是我们的模拟器名称,这里我们给其命名为“Galaxy_Nexus_4.4.2”。大家在起名字的时候,最好使模拟器的名称有意义并和后续设备对得上,同时最好能够将模拟器应用的系统版本标示出来,这样看起来就一目了然了。“Device”表示设备,我们从其下拉列表框中选择“Galaxy Nexus (4.65'',720 x 1280:xhdpi)”,代表设备的型号是“Galaxy Nexus”,而括号内部的“(4.65'',720 x 1280:xhdpi)”,表示手机主屏幕大小为4.65英寸,主屏分辨率为720 x 1280像素。“Target”表示Android系统的版本信息和对应的API版本号,“Android 4.4.2 - API Level 19”中“-”前面的信息即为Android系统版本信息,而后面的是API的版本号。“CPU/ABI”表示应用处理器的型号信息,列表框提供了目前的两款主流处理器型号,即ARM (armeabi-v7a)和Intel Atom (x86)。“Keyboard”表示键盘,后面的复选框“hardware keyboard present”表示是否支持硬件键盘。“Skin”英文的原意是皮肤的意思,在这里表示模拟器外观和屏幕尺寸,其下拉列表框提供了一些不同屏幕分辨率,如HVGA、QVGA、WVGA等选项,这些术语都是指屏幕的分辨率。“Front Camera和Back Camera”表示前、后置摄像头,有的时候我们要模拟它。若要选择前置摄像头“Front Camera”,请在下拉框中选择“Webcam0”,其会调用电脑的摄像头;而后置摄像头则选择下拉框的任意一项即可。我们可以根据想要的效果来进行设置。“Memory Options”表示内存选项,“RAM:1024”表示其有1GB的内存,RAM(Random Access Memory,随机存取存储器,又称作“随机存储器”)是与CPU直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中程序的临时数据存储媒介。Android系统是运行在Dalvik虚拟机上的,“VM Heap”就是指虚拟机最大占用内存,也就是单个应用的最大占用内存,这里其值为64,代表64MB。“Internal Storage”表示内部存储,即手机自带存储大小为200MB,内部存储就是将数据保存在设备的内部存储器中。“SD Card”表示SD卡的大小,其单位默认也是MB,当然如果我们需要选择其他存储单位,也可以从下拉列表中进行选择。单击“OK”按钮,对上述设置进行保存,则创建了一个名称为“Galaxy_Nexus_4.4.2”的模拟器,如图1-36所示。

图1-36 “Galaxy_Nexus_4.4.2”模拟器相关信息

我们可以根据自己的需要添加多个模拟器设备,关于如何使用模拟器设备这里想和大家一起来分享一下。

(1)模拟器在我们没有物理手机设备时,对调试测试脚本程序非常有帮助;

(2)模拟器的执行效率要比同配置的真实手机设备低;

(3)模拟器因为其相关的参数可配置,所以可以模拟操作系统版本的升级情况;

(4)模拟器因为其相关的参数可配置,所以建议大家执行测试脚本用例时可以在低版本的系统测试其兼容性问题;

(5)模拟器和真实的物理设备还是有差别的,所以强烈建议大家在做实际的自动化测试时还是要用真实的物理设备。

前面我们建立了一个模拟器,下面将给大家讲解,如何来启动这个模拟器。

首先,在“Android VirtualDevices”列表中,选择我们刚才建立的“Galaxy_Nexus_4.4.2”模拟器,然后单击“Start…”按钮,如图1-37所示。

图1-37 “Galaxy_Nexus_4.4.2”模拟器相关信息

在弹出的图1-38所示界面中,单击“Launch”按钮。

图1-38 “Launch Options”对话框信息

随后弹出图1-39所示对话框,我们不需要对该对话框进行任何操作,接下来耐心等待。

图1-39 “Launch Options”对话框信息

由于计算机配置的不同,模拟器启动所耗费的时间也不尽相同,通常来说其启动时间要大于两分钟,所以需要大家有一定的耐心,这也是我们提倡使用真实物理设备的一个原因,当模拟器启动后,将显示图1-40所示界面信息。

图1-40 “Galaxy_Nexus_4.4.2”启动后的显示效果界面信息

从图1-40中,我们不难看出其界面和手机显示屏幕没有差异,可以通过鼠标单击“锁”图标,按住鼠标向右划动对模拟器进行解锁,解锁后的界面如图1-41所示。

图1-41 解锁后的显示效果界面信息

模拟器同样具备Home键、Back键、最近启用的应用程序键等,它和我们平时应用的手机设备的功能无差别,Home键能够使我们在任何时候都可以回到桌面,Back键则返回到上一个界面,最近启动的应用程序键可以展示最近启用过的应用程序列表供选择,当然在操作的过程中可能会涉及一些输入操作,这时我们笔记本上的键盘就成为了输入设备。

前面已经完成了Android开发环境的搭建工作,现在就让我们一起来编写一个简单的Android程序。这里我们要实现一个两个整型数字相加的程序。

启动Eclipse,单击“File > New > Android Application Project”菜单项,如图1-42所示。

图1-42 创建一个Android项目的菜单操作步骤

在弹出的图1-43所示界面中,“Application Name”表示应用名称,如果后续我们将该应用安装到手机设备上,会在手机上显示该名称,这里我们给其起名为“CalculatorOfTwoNum”。

图1-43 创建一个Android项目的对话框信息

“Project Name”表示项目名称,在项目创建完成后该名称会显示在Eclipse左侧的Package Explorer中,这里我们保留其自动生成的内容,即“CalculatorOfTwoNum”。“Package Name”表示项目的包名,Android系统是通过包名来区分不同应用程序的,因此要保证包名的唯一性,这里我们将其命名为“com.yuy.calculatoroftwonum”。“Minimum Required SDK”表示程序运行需要的最低兼容版本,这里我们保留其默认值,即Android 4.0版本。“Target SDK”表示目标版本,通常我们要在该版本经过非常全面的系统测试,这里我们选择Android 4.4版本。“Complie With”表示程序将使用那个版本的SDK进行编译,这里我们也选择Android 4.4版本。“Theme”表示程序的UI所使用的主题,这里我们选择其默认的“Holo Light with Dark Action Bar”主题。

单击“Next”按钮,进入到图1-44所示对话框,这个对话框可以对项目的一些属性信息进行配置,如是否创建启动图标、创建活动和项目的存放位置等内容,我们不做修改,保留其默认值。单击“Next”按钮,将出现图1-45所示界面,在这个对话框中我们可以配置应用的启动图标,通常启动图标是一个应用的门面,必须好好设计来吸引用户的眼球,但作为一个简单的示例程序,我们可以保留其默认的设置不做更改,单击“Next”按钮,出现图1-46所示界面。

图1-44 项目配置对话框信息

图1-45 项目启动图标配置对话框信息

图1-46 项目创建活动对话框信息

如图1-46所示,我们可以在该对话框选择要创建活动的类型,这里选择创建一个空白活动,也就是其默认的选项,单击“Next”按钮,将出现图1-47所示界面。

图1-47 空白活动对话框信息

在弹出的图1-47所示界面中,包括了2项内容,即“Activity Name”和“Layout Name”,其中“Activity Name”表示给新建的空白活动起的名字,这里保留“MainActivity”,“Layout Name”是针对这个活动的布局文件名字,我们也保留“activity_main”这个名字。然后,单击“Finish”按钮,完成新项目的创建工作,将出现图1-48所示界面。

图1-48 “CalculatorOfTwoNum”相关信息

在做任何事情之前,大家都要想好怎样去实施。这里我们想做一个基于图形界面的手机应用,作者用“画笔”程序做了一个简单的应用预实现的界面,供大家参考,如图1-49所示。

图1-49 预实现的“CalculatorOfTwoNum”应用的相关界面信息

下面,我们就来实现这个小的手机应用程序。首先来实现布局文件,将相应标签、文本框和按钮控件放到图1-49所示的相应位置。当然有两种方式可以实现,一种方式是直接从图 1-48 所示的控件面板中拖放控件到右侧的活动中,另外一种方式是直接修改“activity_main.xml”文件。这里我们选择第二种方式,双击“res”目录下的“layout”子目录中的“activity_main.xml”文件,然后选择右侧的“activity_main.xml”页,如图1-50所示。

图1-50 修改“activity_main.xml”布局文件的操作信息

将“activity_main.xml”文件修改为如下内容。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="com.yuy.calculatoroftwonum.MainActivity" >

<EditText     android:id="@+id/edtnum1"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignParentRight="true"     android:layout_alignTop="@+id/edtnum1"     android:ems="10"     android:inputType="number" > <requestFocus /> </EditText>   <EditText     android:id="@+id/edtnum2"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignLeft="@+id/edtnum1"     android:layout_below="@+id/edtnum1"     android:layout_marginTop="27dp"     android:ems="10"     android:inputType="number" >   </EditText>   <TextView     android:id="@+id/txtnum2"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignBottom="@+id/edtnum2"     android:layout_toLeftOf="@+id/edtnum2"     android:text="@string/num2" />   <TextView     android:id="@+id/txtnum1"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_above="@+id/edtnum2"     android:layout_alignLeft="@+id/txtnum2"     android:text="@string/num1" />   <Button     android:id="@+id/btncalc"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignLeft="@+id/txtnum2"     android:layout_below="@+id/edtnum2"     android:layout_marginTop="70dp"     android:text="@string/calc" />   <Button     android:id="@+id/btnexit"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignBaseline="@+id/btncalc"     android:layout_alignBottom="@+id/btncalc"     android:layout_alignRight="@+id/edtnum2"     android:text="@string/exit" />   </RelativeLayout>

布局文件创建好以后,我们可以切换到图形布局,来看一下效果,如图1-51所示。

图1-51   “activity_main.xml”布局文件的图形化界面信息

从图1-51可以进一步确认它实现了我们预设计界面的需求。也许细心的读者已经从上面的布局文件中发现了以下一些问题。

(1)在上面的配置文件中,并没有出现“数值1:”“数值2:”“求和计算”和“退出”汉字。

(2)上面的布局文件是一个XML文件,那么在XML中不同的标签表示什么控件呢?

下面我们就主要针对这两个问题向大家介绍一下,第一个问题为了解决日后手机应用版本的国际化问题,开发人员通常不直接把文本标签、按钮名称直接写到对应控件的属性中,而是通过一个配置文件来进行设置,这样就可以根据不同国家应用不同的语言,加载不同的配置文件,而不用再每次编译不同的安装包进行分发。这里对应汉字的标题都存放在“res”目录下“values”子目录的“strings.xml”文件中,如图1-52所示。

图1-52   “stings.xml”文件信息

为了让大家看得更清楚,这里将“strings.xml”文件内容展示如下。

<?xml version="1.0" encoding="utf-8"?>
<resources>

<string name="app_name">CalculatorOfTwoNum</string>
<string name="num1">数值1:</string>
<string name="num2">数值2:</string>
<string name="calc">求和计算</string>
<string name="exit">退出</string>
<string name="action_settings">Settings</string>

</resources>

从这个XML文件中,我们可以看到定义了很多标签。第一个标签“<string name="app_name">CalculatorOfTwoNum</string>”定义了名称“app_name”,其值为“CalculatorOfTwoNum”这样的一组键值对。它将会在另一个非常重要的文件,即“AndroidManifest.xml”文件中得到应用,在后续内容中我们将会介绍到。第二个标签“<string name="num1">数值1:</string>”,定义了名称为“num1”的键值,其值为“数值1:”。我们不难理解在“activity_main.xml”布局文件中“android:text="@string/num1"”引用的就是“数值1:”。后续的内容类似,就不再进行赘述说明。下面再说一下第二个问题,在布局文件中,用“<RelativeLayout>”标签来声明一个相对布局,用“<TextView>”来声明一个文本标签控件,用“<EditText>”来声明一个文本框控件,而用“<Button>”来声明一个按钮控件,各个控件标签中还有一些属性来描述其高度、宽度、相对位置等信息,如果想深入地学习,建议大家看系统性书籍,这里作者不再过多地讲述。

接下来,我们实现这个小程序的源代码,单击“src”目录,在“com.yuy.calculatoroftwonum”包下双击“MainActivity.java”文件,打开该文件,如图1-53所示。

图1-53   “MainActivity.java”文件信息

我们将“MainActivity.java”文件的信息修改为以下内容。

package com.yuy.calculatoroftwonum;

import android.R.string;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
  public int add(int num1,int num2){
    return num1+num2;
  }
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button calc = (Button)findViewById(R.id.btncalc);
    calc.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
        EditText t1 = (EditText)findViewById(R.id.edtnum1);
        EditText t2 = (EditText)findViewById(R.id.edtnum2);  
    
        int a= Integer.parseInt(t1.getText().toString());
        int b= Integer.parseInt(t2.getText().toString());  
        String s= Integer.toString(add(a, b));
        Toast.makeText(MainActivity.this,s, Toast.LENGTH_LONG).show();
      }
    }
    );
    Button exit = (Button)findViewById(R.id.btnexit);    
    exit.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        finish();
      }
    });
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }
 
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
      return true;
    }
    return super.onOptionsItemSelected(item);
  }
}}

上面的代码很简单,主要的代码是求和计算部分代码,即下面的内容。

    Button calc = (Button)findViewById(R.id.btncalc);
    calc.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
        EditText t1 = (EditText)findViewById(R.id.edtnum1);
        EditText t2 = (EditText)findViewById(R.id.edtnum2); 
    
        int a= Integer.parseInt(t1.getText().toString());
        int b= Integer.parseInt(t2.getText().toString());  
        String s= Integer.toString(add(a, b));
        Toast.makeText(MainActivity.this,s, Toast.LENGTH_LONG).show();
      }
    }
    );

我们从上面的代码可以看到有findViewById()方法,这个方法是获取布局文件中定义的元素,这里传入的是R.id.btncalc,得到“求和计算”按钮的实例。它涉及了R.java文件,那么就让我们来说一下这个文件。在项目“gen”文件夹下的“com.yuy.calculatoroftwonum”包中会自动生成一个叫“R.java”的文件。在项目中添加的任何资源都会在其中生成一个与之对应的资源ID,请不要自行修改该文件内容,如图1-54所示。得到“求和计算”按钮实例后,通过调用setOnClickListener()方法为该按钮注册一个监听器,单击该按钮就会执行监听器的onClick()方法。

图1-54   “R.java”文件信息

因此就会执行下面的内容。

        EditText t1 = (EditText)findViewById(R.id.edtnum1);
        EditText t2 = (EditText)findViewById(R.id.edtnum2);
    
        int a= Integer.parseInt(t1.getText().toString());
        int b= Integer.parseInt(t2.getText().toString());  
        String s= Integer.toString(add(a, b));
        //显示求和结果
        Toast.makeText(MainActivity.this,s, Toast.LENGTH_LONG).show();

这几条语句的含义是先获得布局中的两个文本框实例,再将“数值1”和“数值2”的文本内容转换为整数赋给整型变量a和b,而后通过add()函数将a与b的和转换为字符串类型赋给字符串类型变量s,最后通过Toast对象的show()方法将求和结果显示出来。

“AndroidManifest.xml”文件位于项目目录之下,如图1-55所示。

图1-55   “AndroidManifest.xml”文件位置信息

它是Android项目的配置文件,程序中定义的四大组件都需要在这个文件里注册。有时候我们需要对SD卡的读写操作、网络等资源进行访问,也需要在该文件中添加相应的权限。还可以在该文件中指定运行这个手机应用所要求的最低兼容版本和目标版本。下面就让我们一起来看一下这个文件的内容。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.yuy.calculatoroftwonum"
  android:versionCode="1"
  android:versionName="1.0" >
  
<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="19" />
  
<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
  
<activity
      android:name=".MainActivity"
      android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>

</manifest>

需要大家注意的是所有的活动都要在“AndroidManifest.xml”文件进行注册后才能被使用,以下配置即为注册“MainActivity”活动,在“MainActivity”前面有一个“.”,它表示当前目录的意思,因为我们的包为“com.yuy.calculatoroftwonum”,也就是“com.yuy.calculatoroftwonum. MainActivity”,“. MainActivity”为其简写形式。为了使“MainActivity”作为这个手机应用的主活动,也就是说能通过单击手机桌面应用的图标直接打开这个活动,就需要加入“<intent-filter>”标签,并加入“<action android:name="android.intent.action.MAIN" />”和“<category android:name="android.intent.category.LAUNCHER" />”,才能使之成为应用的主活动,如下所示。

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

如果没有声明任何一个活动作为主活动,这个程序仍然是可以正常安装的,只是没有办法在手机桌面上看到它,如我们将在后续做自动化测试时讲到的测试程序,将只能看到被测试应用,而看不到测试应用也就是这个原因,这种形式的应用一般作为第三方服务来进行内部调用。

下面的配置用于指定这个程序所支持的最低向下兼容的系统版本和目标版本。

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="19" />

下面的配置用于指定应用的图标、应用标题、序的UI所使用的主题,这些内容引用的也是“strings.xml”和“R.java”这2个文件中的内容。当“allowBackup”标志为“true”时,用户可通过“adb backup”和“adb restore”来进行对应用数据的备份和恢复,这可能存在一定的安全风险。

    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

图1-54中,在项目的最下面有一个名为“project.properties”的文件,该文件的内容如下。

# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir,
# user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

# Project target.
target=android-19

从上面的内容来看,有效的内容仅为“target=android-19”,它指定了编译程序所使用的SDK版本。

结合图1-54项目的结构,我们再向大家介绍和补充说明如下。

“src”:这个目录是存放Java源代码文件的地方。

“gen”:这个目录里的内容都是自动生成的,它主要有一个R.java文件,我们在项目中添加的任何资源其实都会在该文件中生成一个对应的资源ID,请大家不要自行去修改该文件。

“assets”:这个目录主要用于存放一些随程序打包的文件,在程序运行过程中可以动态读取到这些文件的内容。如果程序使用到了WebView加载本地网页的功能,这个目录也将是存放网页相关文件的位置。

“bin”:这个目录主要包含了一些在编译时自动产生的文件,比如安装包文件就会存放在该目录。

“libs”:如果在项目中使用到了第三方的一些jar包,就需要把这些jar包都放在该目录下,放在这个目录下的jar包都会被自动添加到构建路径里去。

“res”:这个目录主要存放项目中使用的所有图片、布局、字符串等资源,前面提到的R.Java文件中的内容也是根据这个目录下的文件自动生成的。当然这个目录下还有很多子目录,图片放在“drawable”目录下,布局放在“layout”目录下,字符串放在“values”目录下。

如果手机模拟器没有启动,则需要开启我们先前创建的手机模拟器,保证其处于运行状态,如图1-56所示。

图1-56 处于运行状态的“Galaxy_Nexus_4.4.2”模拟器

而后选中“CalculatorOfTwoNum”项目,单击鼠标右键,从弹出的快捷菜单中,选择“Run As>Android Application”菜单项,如图1-57所示。

图1-57 运行Android 应用的操作方法

接下来,将会在“Console”的输出内容中看到图1-58所示信息。

图1-58 运行Android应用后Console的输出信息内容

以下内容为其具体的输出信息。

  [2015-05-28 13:46:39 - CalculatorOfTwoNum] ------------------------------
  [2015-05-28 13:46:39 - CalculatorOfTwoNum] Android Launch!
  [2015-05-28 13:46:39 - CalculatorOfTwoNum] adb is running normally.
  [2015-05-28 13:46:39 - CalculatorOfTwoNum] Performing com.yuy.calculatoroftwonum.MainActivity activity 
  launch
  [2015-05-28 13:46:40 - CalculatorOfTwoNum] Automatic Target Mode: using existing emulator 'emulator-5554' 
  running compatible AVD 'Galaxy_Nexus_4.4.2'
  [2015-05-28 13:46:40 - CalculatorOfTwoNum] Uploading CalculatorOfTwoNum.apk onto device 'emulator-5554'
  [2015-05-28 13:46:41 - CalculatorOfTwoNum] Installing CalculatorOfTwoNum.apk...
  [2015-05-28 13:46:53 - CalculatorOfTwoNum] Success!
  [2015-05-28 13:46:54 - CalculatorOfTwoNum] Starting activity com.yuy.calculatoroftwonum. MainActivity on device emulator-5554
  [2015-05-28 13:46:57 - CalculatorOfTwoNum] ActivityManager: Starting: Intent 
  { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] 
  cmp=com.yuy.calculatoroftwonum/.MainActivity }

从上面的输出信息,我们能够清楚地看到执行该应用的操作全过程,可以清楚地看到其启动过程中检测“adb”命令是否可以成功执行,是否能够调用应用的主活动,上传应用的安装包到手机模拟器,安装应用,启动主活动这一完整过程。从输出的信息来看,应用是安装成功的并启动了主活动,所以我们用鼠标操作手机模拟器滑开被锁住的屏幕,如图1-59所示。

图1-59 运行后的应用显示界面信息

我们在“数值1”后的文本框中输入2,在“数值2”后的文本框中输入3,而后单击“求和计算”按钮,会发现在手机屏幕的下方显示一个Toast提示信息“5”,如图1-60所示。

图1-60 验证应用功能的测试信息

单击图1-60所示的“后退键”或者单击“退出”按钮,则回到模拟器的桌面,在桌面上,我们能够看到一个名称为“CalculatorOfTwoNum”的应用,它就是我们的样例程序,如图1-61所示。

图1-61 模拟器桌面相关应用信息

当然也可以使用物理的手机设备作为调试设备,在应用物理的手机设备时,需要保证我们的手机设备可以被一些360手机助手、腾讯手机助手等工具成功访问,如图1-62所示。因为只有被成功识别了,才说明其相关的一些驱动正确安装了,这也是最简单的一种保证手机设备处于可调试状态的处理方式。

图1-62 手机设备被正确识别的相关信息

当使用手机设备作为调试工具时,选中“CalculatorOfTwoNum”项目,单击鼠标右键,从弹出的快捷菜单中,选择“Run As > Android Application”菜单项后,将出现如图1-63所示界面。

图1-63 “Android Device Chooser”对话框信息

从运行的Android 设备列表中选择相应的手机设备,单击“OK”按钮,就会产生和在模拟器上相同的效果,这部分内容就不再进行赘述了。

这里作者强调一点,如果在条件允许的情况下请最好还是通过手机设备进行测试用例脚本的编写、调试以及测试工作,一方面物理设备是真实的设备,模拟器有些情况是模拟不了的、和物理设备还是有一定差异的,另一方面,物理设备的运行速度也明显优于模拟器,所以在本书无特殊说明的情况下,都是通过我的物理手机设备进行调试和测试工作。


瀑布模型是最早出现的软件开发模型,如图2-1所示。该开发模型可以说在软件工程中占有重要的地位,它提供了软件开发的基本框架。其过程是从上一项活动接收该项活动的工作对象作为输入,利用这一输入实施该项活动应完成的内容,给出该项活动的工作成果,并作为输出传给下一项活动。同时评审该项活动的实施,若确认,则继续下一项活动;否则返回前面,甚至更前面的活动。对于经常变化的项目而言,瀑布模型毫无价值。然而,时至今日,越来越多的用户需求已经不再是那么固定,而是在不断地变化,特别是在互联网、游戏行业表现更为突出。结合这种情况,越来越多的软件研发企业已经开始采用敏捷开发来适应不断变化的需求,加快软件研发的进度。敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。换言之,就是把一个大项目分为多个相互联系但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。由此可见,在敏捷开发中,测试显得更加重要,选择一款适合单元测试工具尤为重要。

也许您听说过XUnit,它是一个基于测试驱动开发的测试框架,其为我们在开发过程中使用测试驱动开发提供了一个方便的工具,加快了单元测试速度。XUnit系列的单元测试工具有很多,如JUnit(针对Java)、DUnit(针对Delphi)、NUnit(针对.Net)和PythonUnit(针对Python)等。

图2-1 瀑布开发模型

JUnit由Kent Beck和Erich Gamma建立,是一个Java语言的单元测试框架。它越来越被广泛地应用于基于Java语言的单元测试中,多数Java的开发环境都已经集成了JUnit作为单元测试的工具。

Junit测试是由程序编写人员或专业的白盒测试人员针对源代码进行测试,因为程序编写人员或者白盒测试人员能够接触到源代码,了解程序的内部实现业务逻辑,知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。

前面我们提到了单元测试,那么什么叫单元测试呢?单元测试(Unit Testing),是指对软件中的最小可测试单元进行的检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如在Java中单元指一个类,在C语言里单元指一个函数等。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。通常,我们在编写大型应用系统的时候,都要写成千上万个方法或函数,这些方法或函数的功能通常都是有限的,但是它们却是这个应用系统的根基,只有确保每一个函数或者方法都实现了其意图,才能保证整个系统能够正常、准确地运行。千里之堤溃于蚁穴,如果我们没有对每一个细小的函数或者方法进行系统的单元测试,很有可能最后直接导致整个系统最终被淘汰的结果。由此可见,单元测试十分重要,也非常必要。

我们在进行软件开发过程中,发现在不同的软件企业可能会经常提到一个问题就是“单元测试”应该由谁来做?不同的软件企业可能答案也是不一样的,有的公司单元测试是由程序编写人员实施,有的企业则是由测试人员来实施,我们说其实施的形式无所谓,关键是针对单元测试一定要有实施效果,经过单元测试后的源代码的健壮性、稳定性、执行效率等方面一定要有提升的才是关键所在。也许我们听说过有很多著名的国际软件公司,它们的开发与测试人员的比例是10比1 ,20比1,有的甚至是50比1。看到这个数字,也许我们第一反应就是怎么可能?绝对不会吧?试想一下,如果自己的单位也这样去做后果是什么样呢?最后,我们可以得出一个一致的结论,对于我们公司若是这样的人员配比,开发的软件产品一定是一坨“屎”。结合作者以往在国内的一些中小型软件企业的工作经历来讲,也同意大家得出的最后结论。为什么同样的人员配比,在不同的软件企业得到的最终产品会有如此之大的差异呢?根本原因就是大家对待单元测试的态度不同,最终导致的结果不同。在国内很多程序编写人员认为凡是涉及到测试的,都应该由测试人员来做,不管是单元测试、功能测试、性能测试、安全性测试等统统应该由测试人员来搞,然而大多数公司在人员招聘的时候对测试人员的要求偏低,招聘的人员数量也较少,试想在招聘的时候仅仅要求做功能测试,公司3、5个人测试一个庞大的系统软件,在时间少、任务重的情况下,这些测试人员哪有时间进行其他类型的测试,同时在没有白盒测试经验的积累情况下,突然要求测试人员做基于源代码的单元测试工作是不是有点更加“搞笑”呢。与之不同,在国际上出名的一些大公司,它们的程序编写人员是具备单元测试理论和实践知识的,他们在编写程序代码的时候,就会对其实现的类的方法和模块功能进行单元测试,他们不仅仅把实现其负责的软件功能作为自己的工作内容,还把单元测试同样作为其重要职责之一。而专业的测试人员则主要针对软件集成、一些重要的容易被忽视的测试关键技术的应用做测试,这当然就减少了测试人员的工作量,也相应会提升测试产品的质量了。

由此,我们是不是能够得到一些启发呢?

单元测试应该是程序编写人员必备的一项基本素质,所有的程序编写人员应该把其作为自己工作内容的一部分,而专业的白盒测试人员也应该加强对程序编写人员相关单元测试理论和实践经验的培训与指导,不断提升程序编写人员的理论和实践经验。同时白盒测试人员应该更加关注系统的集成测试、接口测试和那些容易被程序编写人员忽视的一些地方的测试工作。

我们在进行单元测试时,通常应把以下内容作为单元测试的重点。

(1)核心的类方法。

(2)异常处理内容。

(3)边界条件。

(4)算法效率。

(5)业务逻辑。

(6)需求变动频繁之处。

我们在进行单元测试时,通常不应把以下内容作为单元测试的内容。

(1)不测构造函数。

(2)不测Setter()、Getter()方法。

(3)不测框架。

前面我们介绍了一些关于单元测试的知识,相信大家都已经理解了,现在就让我们结合在1.5节实现的样例程序,如图2-2所示,作为我们使用JUnit进行单元测试的例子,来详细向大家介绍JUnit在基于Android项目进行单元测试的应用。

图2-2 两整数求和运行后的界面显示信息

让我们再看一下这个小应用的完整实现源代码。

MainActivity.java文件内容如下。

package com.yuy.calculatoroftwonum;

import android.R.string;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {

  public int add(int num1,int num2){
    return num1+num2;
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button calc = (Button)findViewById(R.id.btncalc);
    calc.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        // TODO Auto-generated method stub
        EditText t1 = (EditText)findViewById(R.id.edtnum1);
        EditText t2 = (EditText)findViewById(R.id.edtnum2);

        int a= Integer.parseInt(t1.getText().toString());
        int b= Integer.parseInt(t2.getText().toString());  
        String s= Integer.toString(add(a, b));
        Toast.makeText(MainActivity.this,s, Toast.LENGTH_LONG).show();
      }
    }
    );
    Button exit = (Button)findViewById(R.id.btnexit);    
    exit.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        finish();
      }
    });
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
      return true;
    }
    return super.onOptionsItemSelected(item);
  }
}

如果我们对基于Android系统项目开发有一定了解的话,相信一定能看出来,其核心代码是计算两个整数相加的函数。我们做单元测试当然也挑选其最核心的函数来进行测试。可以按照如下的步骤来创建一个基于Android项目的测试用例(TestCase)。

第一步:选中“CalculatorOfTwoNum”项目下的“src”目录中的“com.yuy.calculatoroftwonum”包里的“MainActivity.java”文件,单击鼠标右键,从弹出的快捷菜单中选择“New”菜单项,在其弹出的子菜单项中,再选择“JUnit Test Case”选项,如图2-3所示。

图2-3 创建一个单元测试用例操作相关信息

在弹出的图2-4所示对话框中,我们选择“New JUnit 4 test”选项。为了便于我们对测试相关的用例进行管理,同时也为了不和原始的项目源代码混在一块,我们将测试用例放到“com.yuy.calculatoroftwonum.test”包下,因为是针对“MainActivity.java”文件进行的用例设计,所以在Name后的文本框输入“MainActivityTest”,该类的父类我们选择“android.test.AndroidTestCase”,创建“setUp()”和“tearDown()”方法。单击“Next”按钮,出现图2-5所示对话框,这里我们主要针对其关键的“add(int,int)”函数来进行测试,因此选中其前面的复选框,单击“Finish”按钮。

图2-4 新建单元测试用例对话框信息

图2-5 测试方法选择对话框信息

我们在“src”目录下,发现新创建了一个“com.yuy.calculatoroftwonum.test”包,同时Eclipse自动帮我们打开了新建的“MainActivityTest.java”文件,如图2-6所示。

图2-6 新创建的测试用例文件相关信息

为了能够让大家更清楚的看到“MainActivityTest.java”文件内容,我们将其源码贴出来,如下所示。

package com.yuy.calculatoroftwonum.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import android.test.AndroidTestCase;

public class MainActivityTest extends AndroidTestCase {

  @Before
  protected void setUp() throws Exception {
    super.setUp();
  }

  @After
  protected void tearDown() throws Exception {
    super.tearDown();
  }

  @Test
  public void testAdd() {
    fail("Not yet implemented");
  }

}

在生成的测试用例源文件中看到Eclipse自动帮我们创建好了3个函数,即setUp()、tearDown()和testAdd()函数。那么这些函数都是用来做什么的呢?通常setUp()函数用来完成一些初始化的工作,比如创建被测试应用实例或者我们在测试应用的业务时可能会需要登录系统,那么可以将登录放在该部分;tearDown()函数则主要完成一些收尾性的工作,比如释放对象、资源等或者系统的登出;而testAdd()函数就是我们要测试的一些方法、函数,也就是图2-6所示我们选择的测试方法,通常系统自动的帮我们在被测试的方法、函数的前面加上了一个“test”前缀,这是因为在JUnit3里,测试类必须继承TestCase类,方法必须是以“test”开头;在JUnit4里面,采用Annotation的JUnit已经不会霸道的要求必须继承自TestCase了,而且测试方法也不必以“test”开头了,只要以@Test注解来描述即可,无需继承TestCase类。JUnit 设计的非常小巧,但是功能却非常强大。Martin Fowler如此评价JUnit:在软件开发领域,从来就没有如此少的代码起到了如此重要的作用。它大大简化了开发人员执行单元测试的难度,特别是JUnit 4使用Java 5中的注解(Annotation)使测试变得更加简单。为了让大家对JUnit 4的注解有一个认识,这里我简单向大家介绍一下。

JUnit 4使用Java 5中的注解(Annotation),以下是JUnit 4常用的几个Annotation介绍。

@Before:初始化方法;

@After:释放资源;

@Test:测试方法,在这里可以设计一些测试用例,正常的、异常的测试用例;

@Ignore:忽略的测试方法;

@BeforeClass:针对所有测试,只执行一次,且必须为static void;

@AfterClass:针对所有测试,只执行一次,且必须为static void。

我们针对add()函数,想设计3个正常情况下的测试用例,如表2-1所示。当然还可以根据需要设计一些异常情况下的测试用例,因这里只是对JUnit框架的介绍,所以不予过多赘述,如果读者朋友们对此感兴趣,建议看系统的JUnit方面的书籍。

表2-1  用例设计数据表

用 例 序 号 输  入 预 期 输 出
参数1 参数2
1 3 2 5
2 1 99 100
3 1 10000 10001
…… …… …… ……

为此,我们编写的单元测试用例(MainActivityTest.java)源代码如下。

package com.yuy.calculatoroftwonum.test;
 
import com.yuy.calculatoroftwonum.MainActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
import android.test.AndroidTestCase;
public class MainActivityTest extends AndroidTestCase {
  MainActivity myapp = null;
  @Before
  protected void setUp() throws Exception {
    super.setUp();
    myapp = new MainActivity();
  }

  @After
  protected void tearDown() throws Exception {
    super.tearDown();
    myapp = null;
  }

  @Test
  public void testAdd() {
    assertEquals(myapp.add(3,2),5);
    assertEquals(myapp.add(1,99),100);
    assertEquals(myapp.add(1,10000),10001);
  }

}

从上面的测试用例源代码中,我们能清楚的看到引入了JUnit框架的断言语句。什么叫断言呢?JUnit为我们提供了一些辅助函数,用来帮助我们确定被测试的方法是否按照预期的效果正常工作,通常把这些辅助函数称为断言。像在本测试用例源代码中使用的“assertEquals()”函数,myapp.add(3,2)是其第一个参数,它返回的是一个数字,其值应该为5,与第二个参数5是相同的,这样因为它们完全匹配,所以该断言函数的返回值为真。而后面的2个用例的断言应该也为真,关于JUnit的断言还有很多,如assertTrue()、assertNull()、assertSame()等函数,通常它们有一个明显的标记就是函数名称前面都带有“assert”。

接下来,我们要查看JUnit 4的相关库文件是否被配置,单击该项目的任意文件或者是包,而后单击鼠标右键,从快捷菜单中选择“Build Path”>“Configure Build Path …”菜单项,如图2-7所示。

图2-7 项目构建路径配置操作信息

请选择“Libraries”页,查看JUnit 4是否被添加,如果没有请单击“Add Library…”进行添加,如图2-8所示。

图2-8 “Libraries”页信息

还要在“Order and Export”页查看“JUnit 4”是否被选中,如果没有被选中,则需选中该项,如图2-9所示。

图2-9 “Order and Export”页信息

而后,还需要在“AndroidManifest.xml”进行如下配置,“AndroidManifest.xml”文件的具体内容如下。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=http://schemas.android.com/apk/res/android
  package="com.yuy.calculatoroftwonum"
  android:versionCode="1"
  android:versionName="1.0">

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="19" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">

    < uses-library android:name="android.test.runner" />

<activity
      android:name=".MainActivity"
      android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

<instrumentation android:name="android.test.InstrumentationTestRunner"     android:targetPackage="com.yuy.calculatoroftwonum" android:label="Tests for My App" />
</manifest> 

粗、黑字体部分内容为要添加的内容,即在“<application>”增加引用“android.test.runner”的声明,如下所示。

<!-- 在本应用中导入需要使用的包,放在application里面activity外面 -->

     <uses-library android:name="android.test.runner" />

,同时还需要在“<manifest>”中增加“instrumentation”的信息说明,如下所示。

<!-- 记住这个一要放在application外面,不然会出现配置错误信息 -->

<instrumentation android:name="android.test.InstrumentationTestRunner"

  android:targetPackage="com.yuy.calculatoroftwonum" android:label="Tests for My App" />。

上述过程如果配置正确的话,选中“MainActivityTest.java”,单击鼠标右键,选择“Run As”>“Android JUnit Test”,如图2-10所示。

图2-10 运行单元测试用例相关操作

这里我们应用我的手机作为测试设备,在弹出的图2-11设备选择列表,选中我的三星手机,而后单击“OK”按钮。

图2-11 安卓设备选择对话框

我们会发现在我的手机上多了一个被测试的手机应用,如图2-12所示。

图2-12 被测试手机应用图标信息

同时,还发现Eclipse自动会调出“JUnit”视图,如图2-13所示。

图2-13 JUnit视图相关信息

我们可以看到“testAdd”和“testAndroidTestCaseSetupProperly”全部执行成功,上面的进度条全为绿颜色(表示实际的结果和预期的结果一致,也就是断言为真),如果出错则显示为红颜色(表示实际的结果和预期的结果一致,也就是断言为假)。这里我们发现多出来一个“testAndroidTestCaseSetupProperly”,它是怎么来的呢?可以双击它的名称,则出现如图2-14所示信息。

图2-14 “testAndroidTestCaseSetupProperly”相关信息

我们可以看到“testAndroidTestCaseSetupProperly”隶属于“AndroidTestCase.class”类,它主要是判断是否存在上下文,因为不为空所以其为真。而双击“testAdd”则显示其相关内容,如图2-15所示。

图2-15 “testAdd”相关信息

无论我们从事的是手工测试还是自动化测试,有的时候可能会碰到一些时间紧、任务重的情况,有的时候可能在短短的二、三十分钟后就需要将版本部署到互联网环境,无论哪种方式对我们来讲可能都是来不及完成的,此时我们就必须要评估风险,挑一些基础的、重要的业务以及与修改的缺陷相关的内容或者是优先级高的测试用例来执行。那么作为自动化测试工程师的我们又该怎样去实施呢?作为自动化测试工程师,平时在日常的工作中就要养成对自动化测试用例进行分级管理,同时不仅仅是我们要有自动化测试用例,还要有一套框架来管理测试用例按照不同的测试优先级、硬件资源利用率、甚至是结合不同的应急性测试情况手工选择要测试的内容等多种方式来执行这些自动化测试用例,并能够汇集执行结果,分发测试报告等。当然每个单位测试人员的能力不同、单位的实际情况不同、单位对测试人员的要求不同、单位对自身产品的质量要求也不同,大家要因地制宜,满足单位、研发部门、测试部门对产品的定位、产品质量的定位以及发展战略的一些要求等。言归正传,我们接着讲实施自动化测试另一个很重要的内容,测试集(Test Suite)。测试集(TestSuite)是一系列测试用例(testcase)的集合,我们可以根据需要将不同优先级、不同考察功能内容要运行的测试用例添加到测试集当中,方便测试用例的管理、执行。

下面就让我们一起来了解一下如何应用测试集。启动Eclipse,打开“CalculatorOfTwoNum”项目,然后,选中“src”,单击鼠标右键,从弹出的快捷菜单中选择“New”>“Class”,如图2-16所示。

图2-16 创建Java类的相关操作

图2-17 创建Java类的相关配置

如图2-17所示,我们将该测试集命名为“TestSuiteSample”,仍然放入“com.yuy.calculatoro- ftwonum.test”下,其父类为“junit.framework.TestSuite”,而后单击“Finish”按钮。

图2-18 “TestSuiteSample.java”文件的相关信息

如图 2-18 所示为了让大家了解如何在测试集中执行多个测试用例以及如何仅执行测试用例文件中的特定的测试用例,我们再添加一个测试用例的源文件(MainActivityTest1.java),其代码如下。

package com.yuy.calculatoroftwonum.test;

import com.yuy.calculatoroftwonum.MainActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import android.test.AndroidTestCase;

public class MainActivityTest1 extends AndroidTestCase {
  MainActivity myapp = null;
  @Before
  protected void setUp() throws Exception {
    super.setUp();
    myapp = new MainActivity();
  }

  @After
  protected void tearDown() throws Exception {
    super.tearDown();
    myapp = null;
  }

  @Test
  public void Add测试用例1() {
    assertEquals(myapp.add(3,2),5);
  }

  public void Addtest2() {
    assertEquals(myapp.add(3,22),26);
  }  

  public void Addtest() {
    assertEquals(myapp.add(3,2),5);
  }  
}

从上面的代码我们可以看到,我们添加了3个测试用例,即Addtest()、Add测试用例1()和Addtest2(),也许大家已经发现了2个问题,第一个问题是我们发现在用例函数的名称中包含了中文,这是可以的,如果有此需要可以这样写。第二个问题是,我们故意写错了一个断言就是Addtest2()中的“assertEquals(myapp.add(3,22),26);”本来正确的预期输出应该为“25”,这里我们却故意的写错了,期望值写成了“26”。

这里我们修改“TestSuiteSample.java”文件内容,最终其源代码如下所示。

package com.yuy.calculatoroftwonum.test;

import junit.framework.Test;
import junit.framework.TestSuite;

public class TestSuiteSample extends TestSuite {
 public static Test suite() { 
  TestSuite testasuite = new TestSuite("test");
  testasuite.addTestSuite(MainActivityTest.class);
  testasuite.addTest(TestSuite.createTest(MainActivityTest1.class,"Add测试用例1"));  
  testasuite.addTest(TestSuite.createTest(MainActivityTest1.class,"Addtest2"));  
  testasuite.addTest(TestSuite.createTest(MainActivityTest1.class,"Addtest"));    
  return testasuite;
 }
}

从上面的源代码,我们不难发现" TestSuiteSample"类是从"TestSuite"中继承下来的,其定义了一个名为"suite"的静态函数,这是JUnit要求的做法,JUnit通过这种方式才能发现测试集的实际定义,接下来定义了这个测试集的名称为“test”,而TestSuite类提供了2个方法,即addTestSuite()和addTest()方法,“testasuite.addTestSuite(MainActivityTest.class);”就是“MainActivityTest”中的所有测试用例都添加到我们定义的“test”测试集中,而应用addTest()方法就可以添加特定的测试用例,比如这里我们应用“testasuite.addTest(TestSuite.createTest (MainActivityTest1.class,"Add测试用例1"));”,就将“Add测试用例1”测试用例,添加到“test”测试集中,后续用类似的方法将“Addtest2”和“Addtest”都加入到“test”测试集中。

接下来,我们选择“TestSuiteSample.java”文件,单击鼠标右键,选择“Run As”>“Android JUnit Test”菜单项,如图2-19所示。

图2-19 运行测试集相关操作信息

这里我们仍然应用我的手机作为测试设备,在弹出的图2-20设备选择列表,选中我的三星手机,而后单击“OK”按钮。

图2-20 安卓设备选择对话框

我们会发现在我的手机上多了一个被测试的手机应用,如图2-21所示。

图2-21 被测试手机应用图标信息

同时,还会发现Eclipse自动会调出“JUnit”视图,如图2-22所示。

图2-22 JUnit视图相关信息

我们可以看到运行显示为红色,说明有的测试用例执行是失败的,再看上方的“Runs:5/5 Errors:0 Failures:1”,表示运行了5个测试用例,失败1个,所以就为红颜色了。再往下看,下方是我的设备相关信息,在其下对应的是2个以完整的测试类命名,其下包含对应执行的该类测试用例名称,同时可以发现它们的左侧都有一个对应的状态图标,即:。我们可以看到“com.yuy.calculatoroftwonum.MainActivityTest”下的“testAdd”和“testAndroidTestCaseSetupProperly”全部执行成功,而“com.yuy.calculatoroftwonum. MainActivityTest1”下的“Add测试用例1”和“Addtest”是执行成功的,而“Addtest2”是执行失败的,我们可以双击Addtest2,则在JUnit下方输出具体的错误信息,如图2-23所示。

图2-23 JUnit视图“Addtest2”测试用例对应的相关错误信息


相关图书

可用性测试手册(第2版)
可用性测试手册(第2版)
妙手回春:网站可用性测试及优化指南(修订版)
妙手回春:网站可用性测试及优化指南(修订版)
提高转化率!网页A/B测试与多变量测试实战指南
提高转化率!网页A/B测试与多变量测试实战指南

相关文章

相关课程