google官网上为开发者们介绍了Espresso测试框架,在之前的文章中已经讲到,该文章主要讲利用Espresso框架时如何获得测试代码覆盖率。
写了个例子在Github上:
git clone https://github.com/LxxCaroline/EspressoJacocoSample.git
project: EspressoJacocoSample
--module: app
--module: mylibrary
在该工程中有两个模块,app和mylibrary,app依赖mylibrary,我在app下面写了测试代码,想要测测试代码对于mylibrary的覆盖率。
先看下app中build.gradle的配置
apply plugin: 'com.android.application' apply plugin:'jacoco' jacoco{ toolVersion "0.7.4.201502262128" } android { compileSdkVersion 15 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.example.hzlinxuanxuan.espressojacocosample" minSdkVersion 9 targetSdkVersion 15 versionCode 1 versionName "1.0" testInstrumentationRunner "com.example.hzlinxuanxuan.espressojacocosample.JUnitJacocoTestRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug{ testCoverageEnabled true } } packagingOptions { exclude 'LICENSE.txt' } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') debugCompile project(path: ':mylibrary', configuration: 'debug') releaseCompile project(path: ':mylibrary', configuration: 'release') // Testing-only dependencies androidTestCompile 'com.android.support.test:runner:0.3' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2' compile files('libs/junit-4.12.jar') } task jacocoTestReport(type:JacocoReport,dependsOn:"connectedAndroidTest"){ group="Reporting" description = "Generate Jacoco coverage reports" //exclude auto-generated classes and tests def fileFilter=['**/R.class', '**/R$*.class', '**/Manifest*.*', '**/BuildConfig.*', 'android/**/*.*', ] def debugTree=fileTree(dir: "${rootDir}/mylibrary/build/intermediates/classes/debug", excludes: fileFilter) def sdkSrc="${rootDir}/mylibrary/src/main/java" //指明对哪个目录下的代码进行绘制覆盖率统计图标 sourceDirectories=files([sdkSrc]) //指明对哪个目录下的代码进行覆盖率统计 classDirectories=files([debugTree]) additionalSourceDirs=files([ "${buildDir}/generated/source/buildConfig/debug", "${buildDir}/generated/source/r/debug" ]) executionData=fileTree(dir:project.projectDir,includes:['**/*.exec','**/*.ec']) reports{ xml.enabled=true xml.destination="${buildDir}/jacocoTestReport.xml" csv.enabled=false html.enabled=true html.destination="${buildDir}/reports/jacoco" } }其中以下脚本是配置espresso
androidTestCompile 'com.android.support.test:runner:0.3' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'其中以下脚本配置jacoco(生成测试覆盖率的工具)
apply plugin:'jacoco' jacoco{ toolVersion "0.7.4.201502262128" } task jacocoTestReport(type:JacocoReport,dependsOn:"connectedAndroidTest"){ group="Reporting" description = "Generate Jacoco coverage reports" //exclude auto-generated classes and tests def fileFilter=['**/R.class', '**/R$*.class', '**/Manifest*.*', '**/BuildConfig.*', 'android/**/*.*', ] def debugTree=fileTree(dir: "${rootDir}/mylibrary/build/intermediates/classes/debug", excludes: fileFilter) def sdkSrc="${rootDir}/mylibrary/src/main/java" //指明对哪个目录下的代码进行绘制覆盖率统计图标 sourceDirectories=files([sdkSrc]) //指明对哪个目录下的代码进行覆盖率统计 classDirectories=files([debugTree]) additionalSourceDirs=files([ "${buildDir}/generated/source/buildConfig/debug", "${buildDir}/generated/source/r/debug" ]) executionData=fileTree(dir:project.projectDir,includes:['**/*.exec','**/*.ec']) reports{ xml.enabled=true xml.destination="${buildDir}/jacocoTestReport.xml" csv.enabled=false html.enabled=true html.destination="${buildDir}/reports/jacoco" } }当然还有一句重要的话,这句话是指明我们要使用的自定义的runner
testInstrumentationRunner "com.example.hzlinxuanxuan.espressojacocosample.JUnitJacocoTestRunner"
在上面脚本中编写了一个task(如果不理解task可以看该篇文章Android--Gradle的理解),执行该task就可以执行测试用例,并得到结果。
接下来是编写测试代码和自定义runner,在该目录下创建
EspressoTest.java中为测试代码
@RunWith(AndroidJUnit4.class) @LargeTest public class EspressoTest { @Rule public ActivityTestRule<MainActivity> actvRule = new ActivityTestRule(MainActivity.class); @Test public void testCase1() { onView(withId(R.id.btn)).perform(click()); } }JUnitJacocoTestRunner.java:
public class JUnitJacocoTestRunner extends AndroidJUnitRunner { static { final String path = "/data/data/" + BuildConfig.APPLICATION_ID + "/coverage.ec"; System.setProperty("jacoco-agent.destfile", path); } @Override public void finish(int resultCode, Bundle results) { try { Class rt = Class.forName("org.jacoco.agent.rt.RT"); Method getAgent = rt.getMethod("getAgent"); Method dump = getAgent.getReturnType().getMethod("dump", boolean.class); Object agent = getAgent.invoke(null); dump.invoke(agent, false); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } super.finish(resultCode,results); } }
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View view){ LogUtil.d("there is a message"); } }在该该段代码中使用mylibrary模块中LogUtil的函数。
接下来看下mylibrary的build.gradle:
apply plugin: 'com.android.library' android { publishNonDefault true compileSdkVersion 23 buildToolsVersion "22.0.1" defaultConfig { minSdkVersion 9 targetSdkVersion 15 } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } //需要在这里也添加,否则计算出来的覆盖率为0 debug{ testCoverageEnabled true } } } dependencies { compile 'com.android.support:support-v4:19.+' }
testCoverageEnabled true该句代码说明允许对该代码进行统计覆盖率,非常重要。
在最开始的时候我们讲到了一个task,执行该task可以执行测试用例,可以从该处找到task
如果一开始点开gradle,没有显示任何task的话,请点击左上方的刷新按钮,然后选择jacocoTestReport,双击就会执行测试用例。
要注意的是,如果有一个测试用例没有通过,则不能生成覆盖率的报告。
因为初始需求是测试mylibrary中的代码,所以在编写task的时候指定了使用哪个目录下
def debugTree=fileTree(dir: "${rootDir}/mylibrary/build/intermediates/classes/debug", excludes: fileFilter) def sdkSrc="${rootDir}/mylibrary/src/main/java" //指明对哪个目录下的代码进行绘制覆盖率统计图标 sourceDirectories=files([sdkSrc]) //指明对哪个目录下的代码进行覆盖率统计 classDirectories=files([debugTree])如果读者想要测试app下的代码,只需要改成如下即可
def debugTree=fileTree(dir: "${rootDir}/app/build/intermediates/classes/debug", excludes: fileFilter) def sdkSrc="${rootDir}/app/src/main/java" //指明对哪个目录下的代码进行绘制覆盖率统计图标 sourceDirectories=files([sdkSrc]) //指明对哪个目录下的代码进行覆盖率统计 classDirectories=files([debugTree])
生成测试报告之后去该目录下找
app\build\reports\jacoco
结果如下
打开index.html结果如下
当然你可以看到哪些代码被覆盖了