Skip to content

Commit 1950af8

Browse files
authored
Integrate instrumentation tests (#131)
Generate a task that runs unit tests and instrumentation tests for a module and combines their execution data in a single report. Add the option to include instrumentation tests in the global merged report.
1 parent 331fa7b commit 1950af8

File tree

6 files changed

+259
-68
lines changed

6 files changed

+259
-68
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@ Gradle plugin that generates Jacoco reports from a Gradle Project. Android Appli
44

55
### Android project
66

7+
*JVM Unit-Tests*
78
- Task `jacocoTestReport<Flavor><BuildType>`
89
- Executes the `test<Flavor><BuildType>UnitTest` task before
910
- Gets executed when the `check` task is executed
1011
- Generated Jacoco reports can be found under `build/reports/jacoco/<Flavor>/<BuildType>`.
1112

13+
*Instrumented tests*
14+
- Task `combinedTestReport<Flavor><BuildType>`
15+
- Executes the `test<Flavor><BuildType>UnitTest` and `create<Flavor><BuildType>CoverageReports` tasks before (JVM and instrumented tests)
16+
- Gets executed when the `check` task is executed
17+
- Generated Jacoco reports can be found under `build/reports/jacocoCombined/<Flavor>/<BuildType>`.
18+
Note that this task is only generated, if you set `testCoverageEnabled = true` for your [build type](https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.BuildType.html#com.android.build.gradle.internal.dsl.BuildType:testCoverageEnabled), e.g.
19+
```groovy
20+
android {
21+
buildTypes {
22+
debug {
23+
testCoverageEnabled true
24+
}
25+
}
26+
}
27+
```
28+
1229
Where `<BuildType>` is usually `debug` & `release` unless additional build types where specified.
1330
`<Flavor>` is optional and will be ignored if not specified.
1431

@@ -75,6 +92,7 @@ junitJacoco {
7592
ignoreProjects = [] // type String array
7693
excludes // type String List
7794
includeNoLocationClasses = false // type boolean
95+
includeInstrumentationCoverageInMergedReport = false // type boolean
7896
}
7997
```
8098

src/main/groovy/com/vanniktech/android/junit/jacoco/GenerationPlugin.groovy

Lines changed: 106 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ class GenerationPlugin implements Plugin<Project> {
115115
it.jacoco.includeNoLocationClasses = extension.includeNoLocationClasses
116116
}
117117

118+
subProject.android.jacoco.version = extension.jacocoVersion
119+
118120
Collection<BaseVariant> variants = []
119121
if (isAndroidApplication(subProject)) {
120122
variants = subProject.android.applicationVariants
@@ -129,7 +131,8 @@ class GenerationPlugin implements Plugin<Project> {
129131
variants.all { variant ->
130132

131133
def productFlavorName = variant.getFlavorName()
132-
def buildTypeName = variant.getBuildType().name
134+
def buildType = variant.getBuildType()
135+
def buildTypeName = buildType.name
133136

134137
def sourceName, sourcePath
135138
if (!productFlavorName) {
@@ -139,85 +142,124 @@ class GenerationPlugin implements Plugin<Project> {
139142
sourcePath = "${productFlavorName}/${buildTypeName}"
140143
}
141144

142-
final def testTaskName = "test${sourceName.capitalize()}UnitTest"
143-
final def taskName = "jacocoTestReport${sourceName.capitalize()}"
145+
final def jvmTaskName = "jacocoTestReport${sourceName.capitalize()}"
146+
final def combinedTaskName = "combinedTestReport${sourceName.capitalize()}"
144147

145-
subProject.task(taskName, type: JacocoReport, dependsOn: testTaskName) {
146-
group = 'Reporting'
147-
description = "Generate Jacoco coverage reports after running ${sourceName} tests."
148+
final def jvmTestTaskName = "test${sourceName.capitalize()}UnitTest"
149+
final def instrumentationTestTaskName = "create${sourceName.capitalize()}CoverageReport"
148150

149-
reports {
150-
xml {
151-
enabled = true
152-
destination subProject.file("${subProject.buildDir}/reports/jacoco/${sourceName}/jacoco.xml")
153-
}
154-
csv {
155-
enabled = true
156-
destination subProject.file("${subProject.buildDir}/reports/jacoco/${sourceName}/jacoco.csv")
157-
}
158-
html {
159-
enabled = true
160-
destination subProject.file("${subProject.buildDir}/reports/jacoco/${sourceName}")
161-
}
162-
}
151+
addJacocoTask(false, subProject, extension, mergeTask, mergedReportTask, jvmTaskName,
152+
jvmTestTaskName, instrumentationTestTaskName, sourceName, sourcePath, productFlavorName, buildTypeName)
163153

164-
def classPaths = [
165-
"**/intermediates/classes/${sourcePath}/**",
166-
"**/intermediates/javac/${sourceName}/*/classes/**" // Android Gradle Plugin 3.2.x support.
167-
]
154+
if (buildType.testCoverageEnabled) {
155+
addJacocoTask(true, subProject, extension, mergeTask, mergedReportTask, combinedTaskName,
156+
jvmTestTaskName, instrumentationTestTaskName, sourceName, sourcePath, productFlavorName, buildTypeName)
157+
}
158+
}
168159

169-
if (isKotlinAndroid(subProject)) {
170-
classPaths << "**/tmp/kotlin-classes/${sourcePath}/**"
171-
if (productFlavorName) {
172-
classPaths << "**/tmp/kotlin-classes/${productFlavorName}${buildTypeName.capitalize()}/**"
173-
}
160+
return true
161+
}
162+
163+
private static void addJacocoTask(final boolean combined, final Project subProject, final JunitJacocoExtension extension,
164+
JacocoMerge mergeTask, JacocoReport mergedReportTask, final String taskName,
165+
final String jvmTestTaskName, final String instrumentationTestTaskName, final String sourceName,
166+
final String sourcePath, final String productFlavorName, final String buildTypeName) {
167+
final def destinationDir
168+
if (combined) {
169+
destinationDir = "${subProject.buildDir}/reports/jacocoCombined"
170+
} else {
171+
destinationDir = "${subProject.buildDir}/reports/jacoco"
172+
}
173+
174+
subProject.task(taskName, type: JacocoReport) {
175+
group = 'Reporting'
176+
description = "Generate Jacoco coverage reports after running ${sourceName} tests."
177+
178+
if (combined) {
179+
dependsOn jvmTestTaskName, instrumentationTestTaskName
180+
} else {
181+
dependsOn jvmTestTaskName
182+
}
183+
184+
reports {
185+
xml {
186+
enabled = true
187+
destination subProject.file("$destinationDir/${sourceName}/jacoco.xml")
188+
}
189+
csv {
190+
enabled = true
191+
destination subProject.file("$destinationDir/${sourceName}/jacoco.csv")
174192
}
193+
html {
194+
enabled = true
195+
destination subProject.file("$destinationDir/${sourceName}")
196+
}
197+
}
175198

176-
classDirectories = subProject.fileTree(
177-
dir: subProject.buildDir,
178-
includes: classPaths,
179-
excludes: getExcludes(extension)
180-
)
181-
182-
final def coverageSourceDirs = [
183-
"src/main/clojure",
184-
"src/main/groovy",
185-
"src/main/java",
186-
"src/main/kotlin",
187-
"src/main/scala",
188-
"src/$buildTypeName/clojure",
189-
"src/$buildTypeName/groovy",
190-
"src/$buildTypeName/java",
191-
"src/$buildTypeName/kotlin",
192-
"src/$buildTypeName/scala"
193-
]
199+
def classPaths = [
200+
"**/intermediates/classes/${sourcePath}/**",
201+
"**/intermediates/javac/${sourceName}/*/classes/**" // Android Gradle Plugin 3.2.x support.
202+
]
194203

204+
if (isKotlinAndroid(subProject)) {
205+
classPaths << "**/tmp/kotlin-classes/${sourcePath}/**"
195206
if (productFlavorName) {
196-
coverageSourceDirs.add("src/$productFlavorName/clojure")
197-
coverageSourceDirs.add("src/$productFlavorName/groovy")
198-
coverageSourceDirs.add("src/$productFlavorName/java")
199-
coverageSourceDirs.add("src/$productFlavorName/kotlin")
200-
coverageSourceDirs.add("src/$productFlavorName/scala")
207+
classPaths << "**/tmp/kotlin-classes/${productFlavorName}${buildTypeName.capitalize()}/**"
201208
}
209+
}
202210

203-
additionalSourceDirs = subProject.files(coverageSourceDirs)
204-
sourceDirectories = subProject.files(coverageSourceDirs)
205-
executionData = subProject.files("${subProject.buildDir}/jacoco/${testTaskName}.exec")
211+
classDirectories = subProject.fileTree(
212+
dir: subProject.buildDir,
213+
includes: classPaths,
214+
excludes: getExcludes(extension)
215+
)
206216

207-
if (mergeTask != null) {
208-
mergeTask.executionData += executionData
209-
}
210-
if (mergedReportTask != null) {
211-
mergedReportTask.classDirectories += classDirectories
212-
mergedReportTask.additionalSourceDirs += additionalSourceDirs
213-
mergedReportTask.sourceDirectories += sourceDirectories
217+
final def coverageSourceDirs = [
218+
"src/main/clojure",
219+
"src/main/groovy",
220+
"src/main/java",
221+
"src/main/kotlin",
222+
"src/main/scala",
223+
"src/$buildTypeName/clojure",
224+
"src/$buildTypeName/groovy",
225+
"src/$buildTypeName/java",
226+
"src/$buildTypeName/kotlin",
227+
"src/$buildTypeName/scala"
228+
]
229+
230+
if (productFlavorName) {
231+
coverageSourceDirs.add("src/$productFlavorName/clojure")
232+
coverageSourceDirs.add("src/$productFlavorName/groovy")
233+
coverageSourceDirs.add("src/$productFlavorName/java")
234+
coverageSourceDirs.add("src/$productFlavorName/kotlin")
235+
coverageSourceDirs.add("src/$productFlavorName/scala")
236+
}
237+
238+
additionalSourceDirs = subProject.files(coverageSourceDirs)
239+
sourceDirectories = subProject.files(coverageSourceDirs)
240+
executionData = subProject.files("${subProject.buildDir}/jacoco/${jvmTestTaskName}.exec")
241+
242+
if (combined) {
243+
// add instrumentation coverage execution data
244+
executionData += subProject.fileTree("${subProject.buildDir}/outputs/code_coverage").matching {
245+
include "**/*.ec"
214246
}
215247
}
216248

217-
subProject.check.dependsOn "${taskName}"
249+
// add if true in extension or for the unit test Jacoco task
250+
def addToMergeTask = !combined || extension.includeInstrumentationCoverageInMergedReport
251+
252+
if (mergeTask != null && addToMergeTask) {
253+
mergeTask.executionData += executionData
254+
}
255+
if (mergedReportTask != null && addToMergeTask) {
256+
mergedReportTask.classDirectories += classDirectories
257+
mergedReportTask.additionalSourceDirs += additionalSourceDirs
258+
mergedReportTask.sourceDirectories += sourceDirectories
259+
}
218260
}
219261

220-
return true
262+
subProject.check.dependsOn "${taskName}"
221263
}
222264

223265
private static addJacocoMergeToRootProject(final Project project, final JunitJacocoExtension extension) {

src/main/groovy/com/vanniktech/android/junit/jacoco/JunitJacocoExtension.groovy

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,11 @@ class JunitJacocoExtension {
2828
* @since 0.6.0
2929
*/
3030
boolean includeNoLocationClasses
31+
32+
/**
33+
* Whether or not to include instrumentation coverage in the final global merged report.
34+
* Note that this will run all instrumentation tests when true.
35+
* @since 0.13.0
36+
*/
37+
boolean includeInstrumentationCoverageInMergedReport = false
3138
}

0 commit comments

Comments
 (0)