No1:

Android既可以用传统的JUnit测试,也可以用Android的instrument测试。

No2:

当我们运行测试的时候,androidTest SourceSet会被构建成一个可以安装到设备上的测试apk,这个测试apk里有很多我们写好的测试用例,它们会被执行,来测试我们的app。

No3:

android{
defaultConfig{
testApplicationId "org.flysnow.app.example121.test"
testInstrumenttationRunner "android.test.InstrumentationTestRunner"
testHandleProfiling true
testFunctionalTest true
}
}

testApplicationId--测试apk的包名

testFunctionTest--是否启用功能测试

testHandleProfiling--是否启用性能分析

testInstrumentationRunner--运行测试使用的Instrumentation Runner

-----------------------------------

最后根据配置生成AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schema.android.com/apk/res/android"
package="org.flysnow.app.example121.test"> <users-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<application>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="org.flysnow.app.example121"
android:handleProfiling="true"
android:functionalTest="true"
android:label="Tests for org.flysnow.app.example121"/>
</manifest>

targetPackage会使用被测试App的包名自动填充

No4:

依赖

dependencies{
androidTestCompile 'com.android.support:support-annotation:23.0.1'
androidTestCompile 'com.android.support:test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
}

会被编译到测试apk中,正式的apk包里没有这些jar库

No5:

测试apk默认是debug模式,但也可以改为release模式

android{
...
testBuildType "release"
}

No6:

运行测试代码:使用./gradlew connectedCheck运行。内部步骤是:

1)使用adnroidAndroidTest任务构建好测试应用和被测试应用,其中欧冠被测试应用又是被assembleDebug任务构建的

2)通过install任务安装这两个应用

3)运行我们写好的测试用例,等运行完之后,卸载两个应用

4)最后测试的结果会被保存在build/androidTest-results目录下

注:测试Application项目不会有被测试的apk生成,只有一个测试apk生成

No7:

本地单元测试--不依赖Android框架或者只有非常少的依赖,直接运行在本地开发机器上,不需要设备或模拟器

比较常用的模拟框架有Mockito和JMock

No8:

针对特定的BuildType和特定的Flavor测试。每一种BuildType,每一种Flavor都有对应的测试用例存放目录

比如:

src/main/java/对应的是src/test/java

src/debug/java/对应的是src/testDebug/java/

src/google/java/对应的是src/testGoogle/java/

No9:

JUnit3和JUnit4的区别:

JUnit的测试用例需要都集成junit.framework.TestCase,并且测试方法要以test为前缀。JUnit4就没有这些限制,测试方法也只需要使用@Test注解进行标注就好了

package org.flysnow.app.example122;

import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat; public class EmailValidatorTest{
@Test
public void emailValidator_CorrectEmailSimple_ReturnsTrue(){
assertThat(EmailValitor.isValidEmail("name@email.com"),is(true));
}
@Test
public void emailValidator_CorrectEmailSimple_ReturnsFalse(){
assertThat(EmailValidator.isValidEmail("name"),is(false));
}
}

执行

./gradlew :example122:test

测试结果在build/reports/tests目录下

No10:

使用Mockito框架

dependencies{
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
}
package org.flysnow.app.example122;

import android.content.Context;

public class Utils{
private Context mContext; public Utils(Context context){
this.mContext = context;
}
public String getAppName(){
return String.valueOf(mContext.getString(R.string.app_name));
}
}
package org.flysnow.app.example122;

import android.content.Context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class)
public class UtilsTest{
private static final String APP_NAME = "Example122"; @Mock
Context mMockContext;
@Test
public void readAppNameFromContext(){
when(mMockContext.getString(R.string.app_name)).thenReturn(APP_NAME); Utils utils = new Utils(mMockContext);
String appName = utils.getAppName();
assertThat(appName,is(APP_NAME));
}
}

1)告诉JUnit4要使用MockitlJUnitRunner

2)模拟Context的对象mMockContext

3)when.thenReturn逻辑,when一定要和Utils里的getAppName方法的逻辑一样,thenReturn告知模拟器期望返回的值

4)使用./gradlew :example 122:test执行查看结果

No11:

Instrument测试--运行在真实的安卓物理机或模拟器上。要生成一个测试apk。下面以AndroidJUnitRunner为例

android{
defaultConfig{
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testApplicationId "con.example.app.test"
}
} dependencies{
compile fileTree(dir: 'libs',include:['*.jar'])
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
}
package org.flysnow.app.example123;

import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest{
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
@Before
public void initSomethind(){}
@Test
public void validSomething(){
mActivityRule.getActivity().findViewById(android.R.id.test1).performClick();
}
}

@LargeTest说明它有更高的权限

@Rule指定规则:要测试的是MainActivity

另外还有其他的库可以使用

dependencies{
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}

No12:

测试选项配置testOptions闭包

android{
...
testOptions{
reportDir = "$project.buildDir/example123/report"
resultsDir = "$project.buildDir/example123/result"
unitTests.all{
jvmArgs '-XX:MaxPermSize=256m'
}
}
}

1)reportDir:用于配置生成测试报告的目录

2)resultsDir:用于配置生成测试结果的目录

3)unitTests:用于控制单元测试的执行--上面是指定启动的JVM的最大非堆内存是256M

---------------------------------------------

把每个库项目的测试报告统一合并查看:android-reporting

只需要在总的build.gradle中配置

apply plugin: 'android-reporting'

然后执行./gradlew deviceCheck mergeAndroidReports -continue

-continue是在测试失败的时候,也可以继续执行其他测试用例

No13:

代码覆盖率--testCoverageEnabled控制菜吗覆盖率统计是否开启

android{
buildTypes{
release{
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
zipAlignEnabled true
}
debug{
testCoverageEnabled = true
}
}
}

另外,要注意配置jacoco时的Android Gradle的版本号

1)如果是1.5.0之前的版本

android{
jacoco{
version = '0.6.2.201302030002'
}
}

2)如果是1.5.0版本,在根项目的build.gradle里配置

buildscript{
repositories{
jcenter()
}
dependencies{
classpath 'org.jacoco:org.jacoco.core:0.7.4.201502262128'
}
}

3)从2.0.0版本开始,不管在根项目,还是子项目都可以使用了

运行

./gradlew createDebugCoverageReport,报告在build/reports/coverage下

No14:

Lint支持--代码、资源的优化工具--lintOptions{}闭包

android{
lintOptions{
abortOnErroe true
warningsAsErrors true
check 'NewApi'
}
}

abortOnError--boolean类型,用于配置Lint发现错误时是否退出Gradle构建

absolutPaths--boolean类型,用于配置错误的输出里是否应该显示绝对路径,默认显示的是相对路径

check--set集合

android{
lintOptions{
check 'NewApi'
}
}

注:NewApi就是一个issue id,终端输入lint --list查看所有可用id,另外,lint --show可以查看详细信息

android{
lintOptions{
def checkSet = new HashSet<String>()
checkSet.add("NewApi");
checkSet.add("InlinedApi")
check = checkSet
}
}

缩写

android{
lintOptions{
check 'InlinedApi','NewApi'
}
}

checkAllWarnings--boolean类型,True表示需要检查所有警告的issue,包括那些默认被关闭的issue,false不检查

checkReleaseBuilds--boolean类型,用于配置在release构建的过程中,Lint是否应该检查致命的错误的问题,默认true,一旦发现有‘fatal’级别的问题,release构建会被终止

disable--用来关闭给定issue id的Lint检查,和check用法一样

enable--用来配置哪些issue id启动lint check,和disable用法相反

explainIssues--boolean类型,用来配置Lint检查出的错误报告是否应该包含解释说明

htmlOutput--File类型,用于配置HTML报告输出的文件路径

android{
lintOptions{
htmlOutput new File("${buildDir}/lintReports/lint-results.html")
}
}

htmlReport--boolean类型,用于配置是否生成HTML报告,默认是true

ignoreWarings--boolean类型,用于配置Lint是否忽略警告级别的检查,只检查错误级别

lintConfig--File类型,用于指定Lint的配置文件,

noLines--boolean类型,如果为true,error输出将不会包含源代码的行号

quiet--boolean类型,表示是否开启安静模式,这样Lint分析的进度或者其他信息将不会显示

severityOverrides--返回一个Map类型结果,用来获取issue的优先级。Map的key是issue id,value是优先级,包括fatal、error、warning、informational、ignore

showAll--boolean类型,用于标记是否应该显示所有的输出

textOutput--File类型,用于指定生成的test格式的报告的路径

textReport--boolean类型,用于配置是否生成text报告

warningsAdErrors--boolean类型,用于配置是否把所有的警告也当成错误处理,默认false

xmlOutput--File类型,用于设置生成xml报告的路径

xmlReport--boolean类型,用于控制是否生成xml格式的报告,默认true

error、fatal、ignore、warning、informational--用来配置issue的优先级,接受的都是issue id作为其参数。error是把给定的issue强制指定为erroe这个优先级

-------------------------

运行./gradlew lint,默认生成报告在output/lint-results.html下

《Gradle权威指南》--Android Gradle测试的更多相关文章

  1. 《Gradle权威指南》--Gradle插件

    No1: 应用插件 apply plugin:'java' apply plugin:org.gradle.api.plugins.JavaPlugin apply plugin:JavaPlugin ...

  2. 《gradle权威指南》--Gradle入门

    No1: Window下搭建Gradle:添加GRADLE_HOME环境变量,然后把GRADLE_HOME\bin添加到PATH系统变量里保存即可.完成后打开CMD,运行gradle -v来验证 No ...

  3. 《Gradle权威指南》--Gradle构建脚本基础

    No1: 设置文件默认名是setting.gradle,放在根目录下,大多数作用都是为了配置子工程 No2: 一个Project包含很多个Task.Task就是一个操作,一个原子性的操作.其实它是Pr ...

  4. 《Gradle权威指南》--Gradle任务

    No1: 多种方式创建任务 def Task ex41CreateTask1 = task(ex41CreateTask1) ex41CreateTask1.doLast{ println " ...

  5. 读书笔记--Android Gradle权威指南(下)

    前言 最近看了一本书<Android Gradle 权威指南>,收获挺多,就想着来记录一些读书笔记,方便后续查阅. 本篇内容是基于上一篇:读书笔记--Android Gradle权威指南( ...

  6. 读书笔记--Android Gradle权威指南(上)

    本篇文章已授权微信公众号 dasu_Android(大苏)独家发布 最近看了一本书<Android Gradle 权威指南>,对于 Gradle 理解又更深了,但不想过段时间就又忘光了,所 ...

  7. Android Gradle 构建工具(Android Gradle Build Tools)是什么?

    转载地址:http://mrfu.me/android/2015/07/17/New_Android_Gradle_Build_Tools/ 译者地址:[翻]一览新的 Android Gradle 构 ...

  8. Gradle系列之Android Gradle插件

    原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...

  9. Gradle系列之Android Gradle基础配置

    原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...

  10. Gradle系列之Android Gradle高级配置

    本篇文章主要在之前学习的基础上,从实际开发的角度学习如何对 Android Gradle 来进行自定义以满足不同的开发需求,下面是 Gradle 系列的几篇文章: Gradle系列之初识Gradle ...

随机推荐

  1. QLabel-标签控件的应用

    label = QLabel('我是李明') #创建标签控件对象.参数:标签中要显示的文本 label.setText('我是明明') 修改标签控件显示的文本 self.label.text() 返回 ...

  2. Jetson tx2的tensorflow keras环境搭建

    其实我一直都在想,搞算法的不仅仅是服务,我们更是要在一个平台上去实现服务,因此,在工业领域,板子是很重要的,它承载着无限的机遇和挑战,当然,我并不是特别懂一些底层的东西,但是这篇博客希望可以帮助有需要 ...

  3. python cookbook 笔记一

    因为有些代码只有在python3里可以正常运行,所以最好配两个虚拟环境 安装虚拟环境: pip install virtualenv virtualenv -p /usr/bin/python3.5 ...

  4. Linux注销&登陆

    ⒈注销 ①在命令行使用logout,此指令在图形界面无效.

  5. ocos2d-x 3.0坐标系详解--透彻篇 ---- convertToWorldSpace:把基于当前节点的本地坐标系下的坐标转换到世界坐标系中。

    convertToWorldSpace:把基于当前节点的本地坐标系下的坐标转换到世界坐标系中.重点说明:基于...   不一定要是真实的,  convertToWorldSpace 的结果也只是一个新 ...

  6. PYTHON-模块定义 搜索路径

    模块是什么: ***** 模块 是一系列功能的集合体 一个py文件就是一个模块 一个函数就是一个功能 例如 A.py 文件名A.py 模块名 A 模块有哪些来源 内置 第三方 自定义 模块有四种通用的 ...

  7. PYTHON-函数的定义与调用,返回值,和参数

    函数基础'''1. 什么是函数 具备某一功能的工具->函数 事先准备工具的过程--->函数的定义 遇到应用场景,拿来就用---->函数的调用 函数分类两大类: 1. 内置函数 2. ...

  8. OCM_第十五天课程:Section6 —》数据库性能调优 _SQL 访问建议 /SQL 性能分析器/配置基线模板/SQL 执行计划管理/实例限制

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

  9. CentOS切换为iptables防火墙并进行相关配置

    CentOS切换为iptables防火墙 切换到iptables首先应该关掉默认的firewalld,然后安装iptables服务. 1.关闭firewall: service firewalld s ...

  10. HTTP协议 (1)

    HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议. HTT ...