title: Global code coverage in multi-module Android project: merge code coverage reports (Unit & UI tests)
body: <p>I have an Android app which is made up of 2 modules:</p>
  
  <ul>
  <li><p>App - UI </p></li>
  <li><p>Submodule - has most of the business logic</p></li>
  </ul>
  
  <p>For each of them I have a gradle task to validate code coverage:</p>
  
  <ul>
  <li><p>App: UI Code coverage (Espresso)</p></li>
  <li><p>Submodule: Unit tests code coverage</p></li>
  </ul>
  
  <p>As a requirement for the client, <strong>I need to merge those two reports to get the overall/global code coverage</strong> of the app.</p>
  
  <p>Note: I'm using <strong>Gradle version 3.1.2.</strong></p>
  
  <hr>
  
  <h2>App Gradle file:</h2>
  
  <pre><code>apply plugin: 'jacoco'
  
  android {
  
     testBuildType "uiTest"
  
      ...
  
    buildTypes {
      debug {
          applicationIdSuffix ".debug"
          versionNameSuffix "-debug"
          debuggable true
  
          minifyEnabled false
          shrinkResources false
          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  
  
          matchingFallbacks = ['debug']
      }
  
      // TESTS
  
      // unitTest will be used to run unit tests.
      unitTest.initWith(buildTypes.debug) //Beware the buildType this depends on MUST be above on the gradle file
      unitTest {
          applicationIdSuffix ".unitTest"
          versionNameSuffix "-unitTest"
  
          testCoverageEnabled = true
          matchingFallbacks = ['unitTest', 'debug']
      }
  
      // uiTest will be used to run ui tests.
      uiTest.initWith(buildTypes.debug) //Beware the buildType this depends on MUST be above on the gradle file
      uiTest {
          applicationIdSuffix ".uiTest"
          versionNameSuffix "-uiTest"
  
          testCoverageEnabled = true
          matchingFallbacks = ['uiTest', 'debug']
      }
  
      ...
  </code></pre>
  
  <h2>SubModule Gradle file:</h2>
  
  <pre><code>apply plugin: 'jacoco'
  
  android {
  
     testBuildType "uiTest"
  
     buildTypes {
      debug {
      }
  
      unitTest {
          initWith(buildTypes.debug)
          testCoverageEnabled = true
      }
  
      uiTest {
          initWith(buildTypes.debug)
          testCoverageEnabled = true
      }
  
    ...
  }
  </code></pre>
  
  <p>I've tried several ways, this one below indeed merges the tests.. but the coverage is not appearing correctly:</p>
  
  <h2><strong>The task for creating UI Test coverage in the app:</strong></h2>
  
  <p>//UI Test Coverage filtered (we need to run unit tests of App to be able to use Jacoco to filter)</p>
  
  <pre><code>task createTestReport(type: JacocoReport, dependsOn: [':app:testUnitTestUnitTest', ':app:createUiTestAndroidTestCoverageReport']) {
  
  reports {
      html.enabled = true
  }
  
  def fileFilter = [
          //Android stuff
          '**/R.class',
          '**/BR.class',
          '**/R$*.class',
          '**/BR$*.class',
          '**/BuildConfig.*',
          'android/**/*.*',
          //Data Binding
          '**/*databinding',
          '**/*binders',
          '**/*layouts',
          '**/Manifest*.*',
          '**/*Test*.*',
          "**/services/**/model/**",
          //Utils
          '**/utils/*.*',
          '**/utils/**/*.*'
  ]
  
  //To support Java coverage on Unit tests
  def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/unitTest", excludes: fileFilter)
  //To support Kotlin coverage on Unit tests
  def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/unitTest", excludes: fileFilter)
  
  def mainSrc = "${project.projectDir}/src/main/java"
  def debugSrc = "${project.projectDir}/src/debug/java"
  
  sourceDirectories = files([mainSrc, debugSrc])
  
  
  def appAndroidTests = fileTree(dir: "${buildDir}/outputs/code-coverage/connected/", includes: ["**/*.ec"])
  def appOtherAndroidTests = fileTree(dir: "${buildDir}/outputs/androidTest-results/connected/", includes: ["**/*.ec"])
  
  classDirectories = files([debugTree], [kotlinDebugTree])
  executionData = files("${buildDir}/jacoco/testUnitTestUnitTest.exec", appAndroidTests, appOtherAndroidTests)
  </code></pre>
  
  <p>}</p>
  
  <h2><strong>The task for creating Unit test coverage in the sub-module:</strong></h2>
  
  <p>//Unit Test Coverage filtered</p>
  
  <p>task createTestReport(type: JacocoReport, dependsOn: ['testUnitTestUnitTest']) {</p>
  
  <pre><code>reports {
      html.enabled = true
  }
  
  def fileFilter = ['**/R.class',
                    '**/BR.class',
                    '**/R$*.class',
                    '**/BR$*.class',
                    '**/BuildConfig.*',
                    '**/*databinding/**/*.*',
                    '**/Manifest*.*',
                    '**/*Test*.*',
                    "**/services/**/model/**",
                    'android/**/*.*',
                    '**/utils/*.*',
                    '**/utils/**/*.*']
  
  //To support Java coverage on Unit tests
  def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/unitTest", excludes: fileFilter)
  //To support Kotlin coverage on Unit tests
  def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/unitTest", excludes: fileFilter)
  
  def mainSrc = "${project.projectDir}/src/main/java"
  def debugSrc = "${project.projectDir}/src/debug/java"
  
  sourceDirectories = files([mainSrc, debugSrc])
  
  
  classDirectories = files([debugTree], [kotlinDebugTree])
  executionData = files("${buildDir}/jacoco/testUnitTestUnitTest.exec")
  </code></pre>
  
  <p>}</p>
  
  <h2><strong>The task for creating Global coverage in the app:</strong></h2>
  
  <p>//Global Test Coverage</p>
  
  <p>task createGlobalTestReport(type: JacocoReport,
          dependsOn: [':app:testUnitTestUnitTest', ':app:createTestReport',
                      ':submodule:testUnitTestUnitTest']) {</p>
  
  <pre><code>reports {
      html.enabled = true
  }
  
  def fileFilter = [
          //Android stuff
          '**/R.class',
          '**/BR.class',
          '**/R$*.class',
          '**/BR$*.class',
          '**/BuildConfig.*',
          'android/**/*.*',
          //Data Binding
          '**/*databinding',
          '**/*binders',
          '**/*layouts',
          '**/Manifest*.*',
          '**/*Test*.*',
          "**/services/**/model/**",
          //Utils
          '**/utils/*.*',
          '**/utils/**/*.*'
  ]
  
  // Note: **/reviews/ReviewService*.* was added as BazaarVoice cannot be mocked
  
  //To support Java coverage on Unit tests
  def debugAppTree = fileTree(dir: "${buildDir}/intermediates/classes/unitTest", excludes: fileFilter)
  //To support Kotlin coverage on Unit tests
  def debugKotlinAppTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/unitTest", excludes: fileFilter)
  
  def debugSdkTree = fileTree(dir: "..//build/intermediates/classes/unitTest", excludes: fileFilter)
  def debugKotlinSdkTree = fileTree(dir: "../submodule/build/tmp/kotlin-classes/unitTest", excludes: fileFilter)
  
  
  def mainAppSrc = "${project.projectDir}/src/main/java"
  def debugAppSrc = "${project.projectDir}/src/debug/java"
  
  def mainSdkSrc = "../submodule/src/main/java"
  def debugSdkSrc = "../submodule/src/debug/java"
  
  
  sourceDirectories = files([mainAppSrc, debugAppSrc,
                             mainSdkSrc, debugSdkSrc])
  
  
  def appAndroidTests = fileTree(dir: "${buildDir}/outputs/code-coverage/connected/", includes: ["**/*.ec"])
  def sdkAndroidTests = fileTree(dir: "../submodule/build/outputs/code-coverage/connected/", includes: ["**/*.ec"])
  
  classDirectories = files([debugAppTree, debugSdkTree,
                            debugKotlinAppTree, debugKotlinSdkTree])
  executionData = files("${buildDir}/jacoco/testUnitTestUnitTest.exec"
          , "../submodule/build/jacoco/testUnitTestUnitTest.exec"
          , appAndroidTests
          , sdkAndroidTests
  )
  </code></pre>
  
  <p>}</p>
  
  <p>Any help would be much appreciated </p>