使用 Espresso 在 Android 中进行测试 - 第 1 部分(设置和基础知识)
设置和基础知识
应用程序开发生命周期中的一个重要阶段是测试,但问题是为什么?
答案是消除应用程序逻辑中ANR 对话框或意外行为的发生。对于 Android,所有 UI 更新都由主线程处理,如果主线程无法在 5 秒内响应用户事件,则会导致应用程序崩溃,并为用户提供关闭应用程序的选项,而不是让用户处于无限等待状态,从而导致糟糕的用户体验。
“应用程序无响应”对话框是主线程(又称 UI 线程)阻塞时间过长时最不希望发生的事件。可能导致此情况的一些情况包括:
渲染更大的图像
在主线程上执行 REST 调用
或者执行任何长时间的计算
其他原因包括异常、无限递归方法调用、缺少类定义、死锁或在旧版本上实现不受支持的功能(如矢量可绘制等)。
测试驱动开发
TDD是一个编写代码、测试和重构代码的递归循环,用于在错误出现时立即解决它们。TDD 列出了在每次修改代码库后测试应用程序运行的方法。TDD 的目标是:
满足指导应用程序设计和开发的要求
为了确定应用程序在不同环境下的性能,请考虑
网络连接
用户输入
服务器稳定性
电池、CPU 和内存优化(内存泄漏)
验证应用程序安全性,防止 SQL 注入和数据安全漏洞
验证特定应用程序 API 的运行情况
“测试导致失败,失败导致理解:- Burt Rutan”
单元和仪器测试
单元测试:单元测试在本地机器上运行,即 Java 虚拟机 (JVM),这意味着它不需要设备或模拟器。单元测试往往很快,因为单元测试不测试任何 Android 特定的依赖项 (Activity、SharedPreferenc) 或使用模拟对象来模仿 Android 框架依赖项的行为。
单元测试位于package-name/src/test/java/下
仪器测试:仪器测试专门用于测试应用程序的 UI,需要使用模拟器或物理设备来执行测试。Android UI 组件依赖Context来访问应用程序中的资源,如 xml、图像、字符串和其他资源。Context 由 Android 操作系统提供,因此对于仪器测试,上下文由Instrumentation API 提供,用于跟踪 Android 操作系统与应用程序之间的交互,即向活动生命周期、环境详细信息等发出命令。
仪器测试位于package-name/src/androidTest/java/下
测试术语
- AndroidJUnitRunner:AndroidJUnitRunner是一个 JUnit 测试运行器,可让您在 Android 设备上运行 JUnit 测试,同时提供注释以简化测试过程。对于仪器测试,测试类必须以 @RunWith(AndroidJUnit4.class) 为前缀。
- 注解:@Test注解用于标记要测试的方法,带有@Before注解的方法将首先执行以设置测试环境,带有@After注解的方法将在最后执行。@LargeTest注解用于指示测试持续时间可以大于 1 秒。
- Espresso:它是一个 Android 测试框架,用于编写用户界面交互的测试。
- Mockito:Mockito经常用于单元测试,创建虚拟对象来模仿对象的行为。
使用 Espresso 进行仪器测试
Espresso 是 Google 为 UI(用户界面)测试开发的测试框架,其中包括按钮、列表、片段等所有视图组件。Espresso 是测试 API 的集合,专为仪表/UI 测试而设计。UI 测试可确保用户不会遇到不良交互或意外行为。
Espresso 有各种选项可在屏幕上查找“视图”、执行操作以及验证“视图”的可见性和状态/内容。
onView(withId(R.id.my_view)) // onView() is a ViewMatcher</strong>
.perform(click()) // click() is a ViewAction</strong>
.check(matches(isDisplayed()));// matches(isDisplayed()) is a ViewAssertion
ViewMatcher :使用withId(R.id.id_of_view)、withText("通过视图上的文本查找")在 UI 层次结构(xml 布局组件的树结构)中定位视图。
ViewActions :用于使用ViewInteraction.perform(click(),doubleClick())或click()、longClick()、doubleClick () 、 swipeDown()、 swipeLeft() 、swipeRight ()、swipeUp()、typeText()、pressKey()、clearText()等在 UI 视图中执行特定操作或一组操作。
ViewAssertion :使用ViewInteraction.check(断言方法)断言视图的状态,其中断言方法可以是isDisplayed()、isEnabled()、isRoot()。
设置
- 在build.gradle应用模块中添加 espresso 依赖项:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// AndroidJUnitRunner and JUnit Rules
androidTestCompile 'com.android.support.test:runner:1.0.1'
androidTestCompile 'com.android.support.test:rules:1.0.1'
// espresso support
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.1'
// for intent mocking
androidTestCompile 'com.android.support.test.espresso:espresso-intents:3.0.1'
// for network testing to track idle state
androidTestCompile 'com.android.support.test.espresso.idling:idling-concurrent:3.0.1'
androidTestCompile 'com.android.support.test.espresso:espresso-idling-resource:3.0.1'
// other dependencies
}
- 要启用仪器测试,请添加以下依赖项:
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
完整的build.gradle(应用程序)文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.pavneet_singh.espressotestingdemo"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
//as mentioned above
}
由于未来的更新,您项目中的库版本的值可能会有所不同,其余配置值取决于项目。
关闭默认设备动画
默认动画可能会在 Espresso 测试过程中出现问题,因此建议在测试前关闭设备和模拟器上的动画。
打开“设置”
选择开发者选项(如果未激活,则在“关于设备设置”中多次单击版本/编号)
禁用:
窗口动画缩放
过渡动画比例
动画师时长刻度
第一次使用按钮和 EditText 进行 Espresso 测试
MainActivity包含 Button 和 EdiTtext,我们将对其执行测试以验证可见性、输入的值和点击操作。
使用以下代码设置 MainActivity
MainActivity的activity_main.xml布局源代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.pavneet_singh.MainActivity">
<EditText
android:layout_marginTop="30dp"
android:id="@+id/editTextName"
android:hint="Enter Name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName" />
<Button
android:onClick="setDefaultText"
android:layout_marginTop="60dp"
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clear" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
</LinearLayout>
xml中的onClick属性指向MainActivity中一个处理点击事件的公共方法,如下所示:
package com.pavneet_singh;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.EditText;
import com.pavneet_singh.espressotestingdemo.FruitListActivity;
import com.pavneet_singh.espressotestingdemo.R;
public class MainActivity extends AppCompatActivity {
private EditText editTextName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextName = (EditText)findViewById(R.id.editTextName);
FloatingActionButton fab = (FloatingActionButton) findViewBy
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~