Is there any option to exclude Dagger2 classes from test coverage report in Android Studio
JaCoCo excludes
If you're using JaCoCo, for example using android instrumentation connected tests, you need to configure the excludes (or includes), which, according to the documentation is...
A list of class files to exclude from the report. May use wildcard characters (* and ?). When not specified nothing will be excluded.
Which means you need to match the generated dagger class names. The following rules cover virtually any class generated by dagger-compiler, without matching any of non-generated classes (unless you name your class the same as dagger does...):
excludes = [
'**/*_MembersInjector.class',
'**/Dagger*Component.class', // covers component implementations
'**/Dagger*Component$Builder.class', // covers component builders
'**/*Module_*Factory.class'
]
You can check your generated dagger classes in app/build/generated/source/apt directory after running a build, to see if there are any additional generated classes that you want to match with excludes.
This excludes array is a configuration property of jacoco plugin. Now, where to put this excludes array depends on whether you define your own tasks based on the jacoco plugin, or use a 'higher level plugin' that does this for you. For example using this plugin (you can see the plugin source to see where the excludes are actually applied):
jacocoAndroidUnitTestReport {
excludes += [
'**/*_MembersInjector.class',
'**/Dagger*Component.class',
'**/Dagger*Component$Builder.class',
'**/*Module_*Factory.class'
]
}
Connected tests
If you're running android connected test coverage by setting testCoverageEnabled true in your buildType, unfortunately there is no idiomatic way to declare excludes, since the android gradle plugin doesn't provide such options, and the predefined jacoco report task has the excludes hardcoded. In this case, you have to script your own task with excludes.
IntelliJ test runner
If you're using the IntelliJ test runner, whether the coverage is done by IntelliJ or JaCoCo, you need to put the includes for a test configuration.
Open the Edit Configurations window:
Choose your test config and define includes (classes or whole packages). In this case I included the whole com.google.android.gms package, just as an example:
To exclude dagger generated files, the quickest way is to put all the dagger dependencies in one root package, and include all the other packages in the test configuration.
Exclude files from AndroidStudio index
After many days I found solution: exclusion files from IDE index also exclude them from IDE's code coverage report.
So we need create new File-Type for all codegen files (or only Dagger/Hilt files), and exclude this File-Type from index.
To achieve this you need:
1. Create new File-Type 'Codegen' for codegen-files
Go to Preferences -> File Types, and add new file-type Codegen:
Add this templates (templates may change in future):
*_*Factory.java
*_ComponentTreeDeps.java
*_Factory.java
*_GeneratedInjector.java
*_HiltComponents.java
*_HiltModules.java
*_HiltModules_BindsModule.java
*_HiltModules_KeyModule.java
*_MembersInjector.java
*_ProvideFactory.java
*_SingletonC.java
*_TestComponentDataSupplier.java
BR.java
BuildConfig.java
DataBinderMapperImpl.java
Hilt_*.java
_test_*.java
2. Exclude 'Codegen' from index
Open Go to File, choose tab Files and then click Filter and uncheck Codegen file-type.
That's all!
After this when you will run tests with code coverage (with IntelliJ IDEA runner), matched Codegen-files will be excluded also from code coverage report in IDE.
Note: With this approach you can't get coverage from CLI. If you need get coverage from CLI - use Jacoco.
More recent versions of Dagger generate additional files with slightly different patterns. I had success with the following excludes when using Dagger 2.15
'**/*_MembersInjector.class',
'**/Dagger*Component*.class',
'**/Dagger*Subcomponent*.class',
'**/*Subcomponent$Builder.class',
'**/*Module_*Factory.class',
Related
The code coverage works perfectly fine for me when just set isTestCoverageEnabled = true in my BuildType Android Gradle configuration. It creates 2 tasks
createReleaseUnitTestCoverageReport for release build type and createDebugUnitTestCoverageReport for debug one.
The issue that all source files appear in the report and I would like to exclude some of them - e.g. Dagger generated classes etc.
According to the Android docs the only configuration to change is
testCoverage {
jacocoVersion = "YOUR JACOCO VERSION"
}
and nothing else.
Since there is no jacocoTestReport task all solutions from StackOverflow don't work.
Is there any decent way to configure JaCoCo for Android except creating a custom jacocoTestReport task?
I have a Gradle project containing the two modules app and test, where test contains utilities for testing only. Now I'd like to setup this module, so it doesn't include any outputs into the main configuration of app; even not accidentally.
implementation project(':test') # should fail or not contain any inputs
testImplementation project(':test') # should include all inputs
androidTestImplementation project(':test') # should include all inputs
How do I configure test to behave like this?
I'd assume it would be similarly to how the Android plugin handles configurations for build types and flavors, but I'm also not sure on how to figure this out.
I think these are handled with Gradle consumer attributes. Maybe there's a filter or an attribute which could be applied to it to make it only available to tests.
You could use annotations for that:
https://developer.android.com/studio/write/annotations#visible
Another way would be exclude testing code to new module named as sub_test and use testImplementation or androidTestImplementation of that sub_test module in your test module
Found: Use separate test modules for instrumented tests, which tells the how to do it:
... apply the com.android.test plugin instead of com.android.library.
The java-test-fixtures plugin almost behaves like I wished, just a bit more verbose.
implementation project(':test') # should fail or not contain any inputs
testImplementation testFixtures(project(':test'))
androidTestImplementation testFixtures(project(':test'))
Some other downsides for now
As Tom Tresansky Is the java-test-fixtures plugin incompatible with the Build and run using IntelliJ IDEA setting? asked and answered, the Android Studio doesn't handle the testFixtures source set well.
Also it is not yet available for Kotlin or Android. But as Michael Evans pointed out, there's tasks already open for Android and on YouTrack.
But creating the test fixtures with a Kotlin JVM project and consuming these with an Android project works fine for me.
I am using Dagger 2 library to mock dependencies. While running unit test cases with code coverage it considers these generated dependencies and not the classes used for class under the question.
Is it possible to exclude these classes?
What I tried
Run -> Edit config -> Test coverage -> Exclude Package
Individually adding generated class files, but it doesn't work
Any help here?
I am migrating a quite big and complex legacy project to Gradle.
I have many libraries projects, where each project has its own test subprojects.
The project structure looks as follows:
- LibraryX
-- LibraryXTestsOne
-- LibraryXTestsTwo
- LibraryY
-- LibraryYTests
....
Each library is configured as follows:
The main sourceset contains all the library code
The androidTest sourceset is empty
Each test project is configured as follows:
It lists the parent library as a dependency
The main sourceset is empty
The androidTest sourceset contains all the tests code
With such a configuration I manage to run the test with :libraryTestsA:connectedAndroidTest, but I can't get the test coverage to work. I enable it through
buildTypes{
debug{ testCoverageEnabled true }
}
Apparently the classes of the parent library are not instrumented causing the code coverage to be zero.
Any suggestions?
It turns out that you just need to set testCoverageEnabled to true for all the projects/libraries that the test project depends on.
That will be enough to instrument your code.
You still need to create a custom jacocoReport task though, since the one provided by the android plugin looks up classes and sources in the project main sourceset, which are empty in a configuration like mine.
I have read around, there are a number of extensive answers (like this one) but the Android world evolves so fast that they seem to be a bit outdated and the official documentation still refers to Eclipse with ADT.
I am running AS 1.1 and I am trying to setup simple junit tests to run on the emulator, without Robolectric. If I don't include junit in my build.gradle, it can't find #After, #Before and #Test and I get package org.junit does not exist. Upon adding
// unit tests
androidTestCompile 'junit:junit:4.11'
the error becomes
Error:duplicate files during packaging of APK
[...]/app/build/outputs/apk/app-debug-test-unaligned.apk
Path in archive: LICENSE.txt
Origin 1: [...]/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar
Origin 2: [...]/.gradle/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar
You can ignore those files in your build.gradle:
android {
packagingOptions {
exclude 'LICENSE.txt'
}
}
Following the console suggestion of excluding LICENSE.txt, it then works but it feels like a hack. So I'm wondering, am I maybe missing something? Thanks.
Android Studio unit testing support comes in 1.1 Beta 4 (release announcement) with Gradle plugin version 1.1.0-rc1.
More info in official document.
However it is experimental feature for now. E.g. it breaks installDebug gradle task.
For using JUnit in instrumentation tests there is good guide for Espresso library and another covering new AndroidJUnitRunner.
If it's any use I set up a boiler plate project allowing the use of Unit tests and Espresso tests by the use of switching build variants. You won't need the use of any third party plugins with this.
https://github.com/hitherejoe/Android-Boilerplate