一、概述
在这篇文章中,我们会学习到怎样为android应用作测试,包括如何用android studio进行单元测试、黑盒测试和功能性UI测试。最后我们会讲解一些有关espresso测试框架的高级用法。
读完这篇文章后,我们会学习到:
1.使用MVP设计模式为轻量应用进行架构设计
2.使用Android Studio 和 Gradle 工具运行Android测试
3.使用Junit4框架写单元测试
4.使用 Espresso测试框架和 android测试支持库写UI测试
5.一些Espresso框架的高级应用,包括Espresso-contrib,Espresso-intents 和IdlingResources
6.如何生成测试报告
在开始学习之前,我们需要:
1.Android Studio工具,版本要在2.1+
2.可供测试的小程序样例
3.在Android 2.3.3 或更高的版本中可运行设备或模拟器
4.如果使用物理设备,还必须要一根可连接电脑的USB线。
二、获取可供测试的小程序样例方法
我们可下载zip文件到你的电脑中,它包含了所有的代码,下载zip文件
我们已经为你创建了每一步骤的快照代码。如果你获得了某一分支检查点,你可以从当前的那个检查点继续学习
起先,我们首先导入“step1-5”目录,如果你想要直接到下一个章节,请使用检查点。
zip文件解压后的目录结构和文件:
step1-5目录,它包含写测试用例的所有样例代码
step6目录,使用JUnit4 和 Mockito 框架写测试用例
step7目录,使用Espresso框架写UI测试用例
step8目录,Espresso框架的高级应用之Espresso-Intents框架
step9目录,Espresso框架的高级应用之Espresso-Contrib框架
final目录,这篇文章中用到的所用样例代码
我们也可以从github中直接下载每一个分支,因为我们把每一个检查点设置了单独的分支。
这第一个快照的分支是在分支名为“step1-5”:
$ git clone https://github.com/googlecodelabs/android-testing -b step-1-5
我们将要回到我们使用android studio导入项目并首次运行app的地方。现在,我们可以下载这个样例代码并保存到我们的电脑中。
如果你运行这个app,你会注意到屏幕黑屏并且没有可录入笔记的地方或没有看到任何可操作的按钮。不要着急,稍后我们会完善它。
Notes --- 一个简单的便签应用
在这个章节,你会开发一个简单的便签应用“Notes”。不要担心,我们已经为你准备好了所有的代码。
你能够浏览便签,打开它个并且增加一条新记录或贴上一个照片。在接下来的步骤中,我完成这个app的最终部分,以便我们探索MVP架构和最重要的内容——增加一些测试。
三、android测试简介
运行在终端设备上的移动应用,有不同的屏幕大小、解决方案、处理能力、可变的内容和不同的连接。在所有不同配置的手机设备上和考虑的外部因素手动测试我们的应用是完全不可能的,那么自动化测试正好能帮助我们解决这个问题。
Android Testing Support Library (ATSL) 框架为测试我们android应用提供了强大的支持。它包含可进行兼容性测试框架JUnit4 (AndroidJUnitRunner) 和 可进行功能性UI测试的框架Espresso和UI Automator。你能够在Android Studio IDE 或命令行直接运行这些可测试的api。它是很容易集成到我们开发时的工作流程中。
稍后我们会看到更多细节和怎样使用这些伟大的工具来写自己的测试代码。
四、Model-View-Presenter(MVP)架构设计
一个App的架构设计,有很多种方式。但不是所有的架构都是可测试的,并不是所有的架构都是用明智的方法组织我们的代码,以便我们测试变得非常容易。
一个可测试的架构设计的关键思想是分离我们的app,使它们很容易的维护和独立的测试。一种流行的UI设计模式是Model-View-PresenterModel-View-Presenter 架构,缩写为MVP。
1.Model-View-Presenter设计模式
在我们的app中,我们会使得内部数据模型和被动的视图分离并且通过presenter层来操作我们app的业务逻辑。
2.模型(model)
Model负责提供和存储内部数据
在我们的便笺录入app中,便笺代表Model,每一个便笺又有些属性数据(标题、描述、图片),并且通过数据源和api终端提供数据值(Note被存储在NotesRepository中并通过NotesServiceApi返回数据)。
3.视图(view)
view(不要和android class view混淆,这里仅指单独的用户展示界面)负责展示显示的数据(例如 Note这个model)。用户动作将会被发送到presenter层处理。
在我们的app中,Fragments 代表视图,但本质上讲,它是任何android视图。在我们的app中有三个视图:
- 展示便笺列表的用户接口视图(NotesContract.View),它被自己的fragment(NotesFragment)实现。
- 展示便笺明细的单独视图(NoteDetailContract.View)以及和它相符合的相对应的fragment(NoteDetailFragment)。
- 展示用户录入新便笺的视图(AddNoteContract.View)以及和它相符合的相对应的fragment(AddNoteFragment)。
4.控制者(presenter)
presenter位于model和view之间,它协调UI的内容数据以取保它们同步。特别的是它更新view并且处理视图上被发送的用户事件。presenter也接收来自model的数据,来为展示这些数据到视图中做准备。presenter也负责更新model的数据
在我们的app中有3个presenter:
- NotesPresenter,负责从API中获取便笺列表数据
- NoteDetailPresenter,负责从api中获取某一个便笺明细数据
- AddNotePresenter,负责保存一个新的便笺数据。
更多学习资料
- Android Architecture Blueprints 一个讨论和展示了不同框架工具和不同设计模式的android应用
下面让我们来看一看MVP模式是怎样工作的以及它和我们现有的app代码有什么不同
五.MVP实践
1.使用Android Studio导入这个项目
如果你已经下载了这个zip文件,解压然后在android studio打开名称为step1-5的文件夹(启动android studio,然后选择 File > Open 并且选择“step1-5”目录。你也可以选择settings.gradle文件),如下图:
这是我们第一个快照样例,它包含起始点样例代码。稍后我们也会陆续有其他的子快照样例。
如果你运行这个app,你会注意到一个没有任何便笺和操作按钮的空白页面。稍后我们将会实现这些逻辑。目前,我们来探究一下我们app的架构和设计模式。
2.便笺应用架构:通过package分离特点
使用包来代替分层的方式,我们是为应用的每一个特征通过包来组织代码。这不仅改善了代码的可读性,还使得我们的app模块化,它们可以相互独立的改变而不相互影响。这个app的每一个关键的特征都在自己的包中管理。让我们快速的看一下如下包结构:
Package: | |
| 增加新便笺 |
| 数据:存储便笺,它包含model层 |
| 便笺明细:展示一个单独的便笺详情 |
| 所有便笺列表:展示存储的所有便笺列表 |
| 页面统计 |
| 工具,可以在任何部分使用,例如访问文件 |
每一个有特征的包内都包含一个契约(
Contract)接口,这个接口定义每一个view和presenter回调特征。
这样来写代码,使得每一个类能清楚的知道它是属于那一个特征和怎样相互连接的。
3.探究“Notes”特征:展示所有便笺列表
我们探究的第一个功能就是展示所有便笺列表特征,它是app启动时展示的特征。这个代码在包com.example.android.testing.notes.notes中
让我们看一这些类:
| 我们app整个输入点. 操作 |
| 定义view层的特征 |
| 定义在view和presenter层之间的交互特征 |
| View层的具体实现类 |
| Presenter层,它实现了监听用户动作的接口 |
4.View层
NotesFragment 类属于view特征,它实现了 NotesContract.View定义的view接口
NotesFragment
public class NotesFragment extends Fragment implements NotesContract.View {
...
NotesContract.View接口,我们定义了从view层到presenter层的所有功能。
NotesContract.java
interface View {
void setProgressIndicator(boolean active);
void showNotes(List<Note> notes);
void showAddNote();
void showNoteDetailUi(String noteId);
}
view