Code coverage on Android/Kotlin with Kover and Sonar differs on percents - android

I'm using Kover to get coverage on kotlin and want to share it with sonar, configuration is like this:
plugins {
...
id "org.jetbrains.kotlinx.kover" version "0.4.2"
id "org.sonarqube" version "3.3"
}
sonarqube {
properties {
property "sonar.sourceEncoding", "UTF-8"
...
property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/kover/report.xml"
}
}
project.tasks["sonarqube"].dependsOn "koverReport"
Now, the HTML report of Kover says I have 33% of coverage meanwhile Sonar shows a 10% coverage. What could be the problem?

The simple answer is that they are computed differently: https://community.sonarsource.com/t/sonarqube-and-code-coverage/4725 .

Related

Sonar Jacoco not considering Kotlin androidTest (integration test case) in coverage

I have local and integrated test cases written for my android project. Using Kotlin(1.4.21) Robolectric(4.5.1), sonar(2.7.1), Jacoco(maven plugin 0.8.2)
The problem is that the Sonar and Jacoco is not considering androidTest(integration test case) written in Kotlin for code coverage
However sonar is showing correct coverage for other test cases like-
java unit test cases -> working
koltin unit test case -> working
java integrated test cases -> working
kotlin integrated test cases -> NOT WORKING
Although I have checked the paths I have set for sonar and it's all correct.
properties['sonar.java.binaries'] = files("${buildDir}/intermediates/javac/universalDebug/classes")
properties["sonar.java.binaries"] += files("${buildDir}/tmp/kotlin-classes/universalDebug/")
properties['sonar.java.test.binaries'] = files("${buildDir}/intermediates/javac/universalDebugAndroidTest/classes")
properties['sonar.java.test.binaries'] += files("${buildDir}/tmp/kotlin-classes/universalDebugAndroidTest/")
I have gone through other stackoverflow questions but didn't find same problem. So, I'm unable to find out the issue why sonar is not showing coverage for my integrated test cases written in Kotlin.
Thanks in Advance
UPDATE
within adroidTest folder > I have further 2 packages.
MyApplicationTest> src> com > pkgA
> pkgB
It's considering the Tests files present in pkgA but not the other. I have recently created this pkgB
What could be the possible reason for this? Do I have update some path somewhere?
You might need to do the following
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
Note that there are some issues with Java 11 that might fail your tests so you might want to also exclude jdk.internal as follows
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
excludes = ['jdk.internal.*']
}
Or a little bit verbose option but works:
subprojects {
pluginManager.withPlugin("com.android.library"){
android.testOptions.unitTests.all {
jacoco {
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
}
}
}
pluginManager.withPlugin("com.android.application"){
android.testOptions.unitTests.all {
jacoco {
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
}
}
}
apply plugin: 'jacoco'
}
I suggest you also upgrade your jacoco and sonar plugin versions if possible

How to encrypt passwords in build.gradle with Android 3.3? Getting "Cannot resolve symbol" in IDE

Since update to Android Studio 3.3 we get a weird warning with some legacy code about encrypted gradle parameters.
In build.gradle we have this line:
apply from: "encryption.gradle"
In encryption.gradle we have this content:
afterEvaluate {
android.applicationVariants.all { variant ->
def pwd = "";
variant.productFlavors.each { flavor ->
if (flavor.ext.has("pwd1")) {
pwd = flavor.ext.pwd1
}
}
if (pwd.isEmpty() && variant.buildType.ext.has("pwd2")) {
pwd = variant.buildType.ext.pwd2
}
variant.resValue 'string', 'pwd', encryptPassword(pwd, variant.signingConfig, variant.applicationId)
}
}
def String encryptPassword(String password, signingConfig, String applicationId) {
...
}
In the code we use it like this:
getString(R.string.pwd)
And since the AS update we get the following error:
Cannot resolve symbol 'pwd'
When compiling/building the project everything runs fine because it can find the parameter. But when working in the IDE, all files that try to use R.string.pwd are marked red and show the error message, which is pretty annoying.
Any way to make this go away easily? SuppressWarnings("all") and SuppressLint("all") are not helping.
Is afterEvaluate the right place to do this or would it be better somehow in the defaultConfig section of build.gradle?
Even i was facing similar issues. so i reverted my gradle to 3.2.1 and it works as expected, it might be a technical glitch/issue with gradle 3.3
While i was on gradle 3.3 i tried invalidating cache for android studio, restarted it etc, but nothing solved the issue.

Android and the Fabric (Crashlytics) plugin always generates a UUID (Gradle Kotlin DSL)

I want Fabric to stop generating a UUID on each build. What used to work with Gradle's Groovy DSL does not work with the newer Kotlin DSL. How can I achieve my goal with the Kotlin DSL?
(Gradle version 4.10.2, Fabric 1.25.4)
According to Fabric's documentation, you can add the following to your app's build script
android {
buildTypes {
debug {
// Only use this flag on builds you don't proguard or upload
// to beta-by-crashlytics
ext.alwaysUpdateBuildId = false
and this works. It prevents Fabric from generating a UUID on each debug build. However, if I convert my build script to Kotlin DSL, the following doesn't work
android {
buildTypes {
getByName("debug") {
// Only use this flag on builds you don't proguard or upload
// to beta-by-crashlytics
ext.set("alwaysUpdateBuildId", false)
Fabric ignores this value, now.
I have tried variations, such as the following:
project.ext.set("alwaysUpdateBuildId", false)
rootProject.ext.set("alwaysUpdateBuildId", false)
val alwaysUpdateBuildId by extra(false)
val alwaysUpdateBuildId by project.extra(false)
val alwaysUpdateBuildId by rootProject.extra(false)
None work.
For further reference, the Gradle task generating this value appears to be named :app:fabricGenerateResourcesDebug, and has type DefaultTask.
As Martin Rajniak mentioned, you can only call extra on ExtensionAware objects, with BuildType not being declared as one.
However, during runtime, build types actually are ExtensionAware, which is why this works in Groovy due to its dynamicity, but not in Kotlin where extra in this scope will reference the Project's extensions.
In order to achieve this without Groovy, we can simply cast the build type to ExtensionAware:
android {
buildTypes {
getByName("debug") {
(this as ExtensionAware).extra["alwaysUpdateBuildId"] = false
}
}
}
I have found a workaround to this problem. Create a file, fabric.gradle (Groovy build script!) and place it in your project structure somewhere. It will have the following contents:
// or "com.android.library"
project.pluginManager.withPlugin("com.android.application") {
android.buildTypes.debug.ext.alwaysUpdateBuildId = false
}
Now, in the build script for your module (let's call it app/build.gradle.kts), apply this script plugin:
apply(from = "path/to/fabric.gradle")
This workaround is based on the advice here, in the Kotlin DSL primer.

sonarqube with both androidTest and test covarage

I'm trying to setup sonarqube reporting in my Android project. I currently have trouble with showing all test classes in the sonar UI, the coverage is shown in percentages and currently only the unit test from app/src/test/ are shown as Unit Tests.
My project has a test folder app/src/test/ which contains unit test and I have a androidTest folder app/src/androidTest/ which contain android unit, integration and UI tests. When I run all the tests via gradle the android-gradle plugin generates build/jacoco/testDebugUnitTest.exec and build/test-results/debug/TEST-*Test.xml which contains the jacoco results and coverage report for the unit test in the test folder. Also the android-gradle plugin generates build/outputs/code-coverage/connected/coverage.ec and build/outputs/androidTest-results/connected/TEST-*Test.xml contain the results and coverage reports from the androidTest folder
In my build.gradle I can specify the properties for the sonar plugin.
sonarqube {
properties {
property "sonar.sources", "src/main/java,src/main/res"
property "sonar.tests", "src/test/java,src/androidTest/java"
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.jacoco.reportPath", "${project.buildDir}/jacoco/testDebugUnitTest.exec"
property 'sonar.jacoco.itReportPath', "${project.buildDir}/outputs/code-coverage/connected/coverage.ec"
property "sonar.junit.reportsPath", "${project.buildDir}/test-results/debug" // path to junit reports
}
}
With sonar.junit.reportsPath I can specify which xml report is sent to the sonarqube server. When I change it to build/outputs/androidTest-results/connected I get the androidTest shown as Unit Test on the dashboard. Is there a way to make the sonar plugin look in both directories or merge the results together?
Until https://jira.sonarsource.com/browse/SONAR-4101 is fixed, the only option you have is to write a task that copies your test result files into a single place and configure that as sonar.junit.reportsPath, like this:
task combineTestResultsForSonarqube {
group = "Reporting"
def modules = ["app", "and", "other", "modules"];
doLast {
modules.each { module ->
File combined = file("${module}/build/combined-test-results")
if (combined.exists()) {
combined.deleteDir()
}
combined.mkdirs();
def testDirs = [file("${module}/build/test-results/debug/"),
file("${module}/build/outputs/androidTest-results/connected/")];
testDirs.each { testDir ->
if (!testDir.exists()) {
logging.captureStandardOutput LogLevel.WARN
println "WARNING: ignoring non-existant ${testDir.path}"
return;
}
files(testDir.listFiles()).each { file ->
new File(combined, file.getName()) << file.text
}
}
}
}
}
Paths of course have to be adapted when you have flavors in your build.

Sonar Android Lint no matching issues found

I have got the following trouble: I have installed SonarQube and Android Plugin with "Android Lint" Quality Profile. When I execute my build.gradle script with "Android Lint" profile, sonar-runner plugin works good, but in SonarQube I can see no matching issues found, just zero.
Nevertheless, when I include another profile –not "Android Lint"– I can see a lot of issues. Also in my android SDK when apply it's own lint I can see 157 issues. What it can be?
sonar - version 3.7.4;
android plugin - version 0.1
Your sonar.sources property should point to the root of AndroidManifest.xml file. E.g. if your AndroidManifest.xml file is located in src/main then your build.gradle file should contain:
sonarRunner {
sonarProperties {
...
property "sonar.sources", "src/main"
property "sonar.profile", "Android Lint"
...
}
}
If you need more paths in sonar.sources you can put them as a comma-separated list.
You can find how Sonar Android Plugin determines whether to run the analysis in its source code.
change your sonar properties like this:
apply plugin: "org.sonarqube"
sonarqube {
properties {
property "sonar.projectName", "appa"
property "sonar.projectKey", "appa_app"
property "sonar.projectVersion", "1.0"
property "sonar.analysis.mode", "publish"
property "sonar.language", "java"
property 'sonar.sourceEncoding', "UTF-8"
property "sonar.sources", "./src/main"
//property "sonar.exclusions", "**/*Entity.java"
// property "sonar.exclusions", "src/main/java/com/apparkb/model/**, **/*Entity.java"
property "sonar.host.url", "http://192.168.21.33:9000"
property "sonar.login", "admin"
property "sonar.profile", "testlint"//use your quality profile instead
property 'sonar.import_unknown_files', true
property "sonar.android.lint.report", "./build/outputs/lint-results-debug.xml"
property "sonar.password", "admin"
property "sonar.java.binaries", "build/"
}
}
For creating lint-results-debug.xml you will have to run the below command on studio terminal:
./gradlew lint
It will generate the missing XML report. Be carful, it can generate a report for each build variant (Debug by default will generate build/outputs/lint-results-debug.xml). So you can call lintDebug, lintRelease... dependings on your build variant.
And change the lint properties to:
lintOptions { // set to true to turn off analysis progress reporting by lint
quiet true
// if true, stop the gradle build if errors are found
abortOnError false
// do not ignore warnings
warningsAsErrors true
}
now if you run
./gradlew sonarqube
you will get the results shown its actually the local file report that's actually getting hosted upon the server
Unfortunately if you merely point sonar.sources to src/main, you're going to get issues with all your source because you most likely don't mave minSdkVersion and targetSdkVersion set (it comes from gradle). I've tried setting my source to be some thing like:
build/intermediates/bundles/release,src/main/java
But I still get an inordinate amount of (invalid) errors due to API levels.

Categories

Resources