Ibotta / gradle-aspectj-pipeline-plugin

A Gradle plugin for Android projects which performs AspectJ weaving using Android's bytcode manipulation pipeline.
Apache License 2.0
75 stars 15 forks source link

Plugin seems to make Jacoco Coverage not including coverage from unit tests #12

Closed davidlbudiman closed 3 years ago

davidlbudiman commented 3 years ago

Hi,

I seem to be having a problem in my Android library project. I am trying to create tests for a project that uses code that is hard to test. So, I restructured some of the old code using AspectJ and your plugin. But, when it comes time to generate the coverage report. It keeps on returning 0%, even though when I generate coverage in IntelliJ IDEA it's giving me >0%.

This is the build.gradle that I used

plugins {
    id 'com.android.library'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
    id "kotlin-kapt"
    id "com.ibotta.gradle.aop"
    id "de.mannodermaus.android-junit5"
    id "jacoco"
}

android {
    compileSdkVersion 27

    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        debug {
            testCoverageEnabled true
            ...
        }
    }
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

...

task jacocoTestReport(type: JacocoReport, dependsOn: ['test[FLAVOR]UnitTest', 'create[FLAVOR]CoverageReport']) {

    reports {
        xml.enabled = true
        html.enabled = true
    }

    def fileFilter = [ '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*' ]
    def debugTree = fileTree(dir: "$project.buildDir/preWeave/[FLAVOR]", excludes: fileFilter)
    def mainSrc = "$project.projectDir/src/main/java" // This is the directory the previous team use to place their Kotlin code

    sourceDirectories.setFrom(files([mainSrc]))
    classDirectories.setFrom(files([debugTree]))
    executionData.setFrom(fileTree(dir: project.buildDir, includes: [
            'jacoco/test[FLAVOR]UnitTest.exec', 'outputs/code-coverage/[FLAVOR]AndroidTest/connected/*coverage.ec'
    ]))
}

jacoco {
    toolVersion = "0.8.7"
}

tasks.withType(Test) {
    jacoco {
        includeNoLocationClasses = true
        excludes = ['jdk.internal.*']
    }
}

I read your plugin code and it seems that this code is suspicious to me

    private fun cleanUpAfterWeaving(compileTask: AbstractCompile, preWeaveDir: Provider<Directory>) {
        compileTask.apply {
            project.copy {
                from(destinationDirectory)
                into(preWeaveDir)
            }

            project.delete(destinationDir)
        }
    }

Does this code really do what I think it does? Which is to delete the tmp directory of Kotlin build classes? Because I've read from a StackOverflow post that Jacoco should be directed to the folder where Kotlin compiled the code. So, I first used the postWeave directory to no result. Then I used the preWeave directory, but I'm still getting nothing. Is there anything different between preWeave and tmp directory? If there is, would it be possible not to delete destinationDir?

P.S. This is a great plugin! Thanks for creating this plugin.

eschlenz commented 3 years ago

@david-blacnet

Thanks for the kind words! This issue of Jacoco reporting 0% actually sounds really familiar. I think we ran into this at Ibotta with our core app.

I guess the good news is, that I don't believe it's because of what our plugin is doing. Our coverage reports are working as expected. I just ran tests in one of our app modules and produced the following report. Note, that AccountPresenterImpl is one of the classes we have AOP woven into.

Screen Shot 2021-08-11 at 10 34 31 AM

The question is why does it work for us, and not you? I'm assuming this is a global issue you are experiencing, where none of your tests are showing coverage. Is that accurate?

For what it's worth, we are using a Jacoco Android library. And our configuration for it is very simple, and seems to be working for us. Are you using this, or would you consider trying it to see if it resolves the issue? It seems to greatly clean up the Jacoco configuration, on top of just "working" for us.

@vdelricco Do you recall any other details that might be useful here?

vdelricco commented 3 years ago

Thanks for the tag @eschlenz, I think what you suggested would be good to try regarding the jacoco android plugin.

@david-blacnet the other thing I'll mention is that the 0.8.7 release of Jacoco fixed a lot of issues related to code coverage with Kotlin. When we updated our toolVersion to 0.8.7 like in your example, I found that we were not seeing any of the touted benefits of the new release. Upon further investigation, it seemed we were still having an older version picked up and used.

Adding this block to our root gradle file solved that:

subprojects {
    configurations.all {
        resolutionStrategy {
            eachDependency { details ->
                if ('org.jacoco' == details.requested.group) {
                    details.useVersion jacoco_tool_version
                }
            }
        }
    }
}

where jacoco_tool_version is currently set to 0.8.7.

I don't know if that's the case in your project currently, or that problem was caused by the plugin we use, but figured I'd mention it just in case because the issue you're describing does sound similar to what we experienced before updating jacoco.

davidlbudiman commented 3 years ago

@eschlenz and @vdelricco thanks for your suggestions. I have got it working now!

eschlenz commented 3 years ago

Glad to hear it!