Android Studio 3/Kotlin code coverage

2019-02-12 16:15发布

问题:

My android app is multi module project:

include (android-app/kotlin-android)':application', (pure kotlin)':presentation', (pure kotlin)':domain', (android-library/kotin-android)':dataproviders'

I'm using Junit/Mockito for tests and I have issue with generating code coverage for kotlin android modules only. Tested lines are visible for android studio.

tested class in ui.viewmodel package:

But, for pure kotlin (eg. domain, presentation) test coverage works fine:

I'm using Android Studio 3.0 Canary 8 You can look at my build.gradle files at github:

build.gradle

dependencies.gradle

application.build.gradle

presentation.build.gradle

Example test in android application module:

MostPopularViewModelTest

Example test in pure kotlin module:

MostPopularPresenterTest

Can someone help me with my problem? I tried generate code coverage via Jacoco but it also did not show code coverage.

回答1:

Solution is to add this this gradle task in build.gradle for module:

task copyTestClasses(type: Copy) {
    from "build/tmp/kotlin-classes/debugUnitTest"
    into "build/intermediates/classes/debug"
}

And run:

gradlew copyTestClasses

Then generate code coverage report without problems.



回答2:

Although the solution from @Hype works, it also messes a bit the environment as you end up with kotlin class files and META-INF in the same directory as the class files from java. This might give you some issues running the compilation for a second time.

Another solution would be to just add the path for kotlin classes to jacoco configuration parameter classDirectories. This solution would simply tell jacoco that it needs to evaluate files from two different file trees. The upside is that it does not change your environment. Here's a sample of how you could combine class files from multiple directories, excluding any unwanted files (this is depending on your project setup, you might use dagger and have to exclude dagger generated files):

def javaAndKotlinClassFiles = files(fileTree(dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
                                excludes: ['**/R.class',
                                           '**/R$*.class',
                                           '**/*$ViewInjector*.*',
                                           '**/*$ViewBinder*.*',
                                           '**/BuildConfig.*',
                                           '**/Manifest*.*',
                                           '**/*$Lambda$*.*', // Jacoco can not handle several "$" in class name.
                                           '**/*_Provide*Factory*.*',
                                           '**/*$*$*.*', // Anonymous classes generated by kotlin
                                           '**/*Test*.*', // Test files
                                           '**/*Spec*.*' // Test files
                                ]
                                    ).files)
                    .from(files(fileTree(dir: "${project.buildDir}/tmp/kotlin-classes/${sourcePath}",
                            excludes: ['**/R.class',
                                       '**/R$*.class',
                                       '**/*$ViewInjector*.*',
                                       '**/*$ViewBinder*.*',
                                       '**/BuildConfig.*',
                                       '**/Manifest*.*',
                                       '**/*$Lambda$*.*', // Jacoco can not handle several "$" in class name.
                                       '**/*_Provide*Factory*.*',
                                       '**/*$*$*.*', // Anonymous classes generated by kotlin
                                       '**/*Test*.*', // Test files
                                       '**/*Spec*.*' // Test files
                                    ]).files)
                    )
            classDirectories = javaAndKotlinClassFiles

Here's a nice guide for how to set it up for Java.