I'm trying to set up a sample android studio project in Github which integrates also its CI connected to SonarQube.
I'm having problems with sonarQube due to it says there is no test coverage applied. However there is, in kotlin and with Juni5, but there is no way to set sonar.tests for recognizing it.
this it the sonar-project.properties
test are run fine either locally and in the CI when a branch of the project is build.
Also I've added this
Gradle has been written with Kotlin-DSL.
if you are using gradle there is no need to define the sources and the tests in the sonar-project.properties. The gradle sonarqube task will pick them up automatically based on your sourcesets.
What i think you are missing is a tool to generate the coverage, sonarqube will not generate coverage data for you. SonarQube utilizes in Java eg. JaCoCo so you also need to apply a plugin for that.
so your build gradle (behold this is groovy dsl, but i will provide a link to one in kotlin) will look something like the following code snippet. This will generate everything automatically
plugins {
id 'java'
id 'jacoco'
id 'eclipse' // optional (to generate Eclipse project files)
id 'idea' // optional (to generate IntelliJ IDEA project files)
id "org.sonarqube" version "2.8"
}
repositories {
jcenter()
}
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.6.0')
}
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
sonarqube {
properties {
/*
UPDATE SECTION START
Please fill in your data
*/
property "sonar.projectName", "SonarCloud Github Actions with gradle"
property "sonar.projectKey", "aepfli_SonarCloud-GitHubActions-Gradle-example"
property "sonar.organization", "aepfli"
/*
UPDATE SECTION END
*/
property "sonar.host.url", "https://sonarcloud.io"
}
}
jacocoTestReport {
reports {
xml.enabled = true
}
}
Alternatively if you are looking for an example in kotlin DSL, i can recommend this one from JUnit Pioneer.
I am still not sure how good the support for kotlin is with JaCoCo. if there is a different tool like JaCoCo in the Kotlin world, you can also try to generate and XML report and provide this xml report via property sonar.coverage.jacoco.xmlReportPaths base on Sonarqube doc
Related
I'm doing some in-depth hands-on with Kotlin Multiplatform Mobile and I'm forced to apply Gradle plugins with the legacy way of applying plugins.
I'm using Kotlin DSL for Gradle and I didn't manage to include the kotlin-multiplatform plugin.
Essentially, there are two ways to include a gradle plugin in your project:
via Gradle Plugins DSL (a modern way)
via legacy plugin application (deprecated but more flexible).
I've basically created a very blank gradle project (gradle init), not related to any IDE or any other dependencies, which both are common for KMM projects - to isolate the issue as much as possible.
The build.gradle.kts below works just fine, when run via ./gradlew clean build (via Plugins DSL)
plugins {
id("org.jetbrains.kotlin.multiplatform") version "1.4.10"
}
kotlin {
jvm()
}
repositories {
jcenter()
}
However, this won't work (via legacy plugin application):
buildscript {
repositories {
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10")
}
}
apply(plugin = "org.jetbrains.kotlin.multiplatform")
kotlin {
jvm()
}
repositories {
jcenter()
}
It fails with this error:
* What went wrong:
Script compilation errors:
Line 12: kotlin {
^ Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun DependencyHandler.kotlin(module: String, version: String? = ...): Any defined in org.gradle.kotlin.dsl
public fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec defined in org.gradle.kotlin.dsl
Line 13: jvm()
^ Unresolved reference: jvm
2 errors
It can't resolve the kotlin {} block which is essentially the entry point in KMM projects.
Interestingly, using Groovy instead of Kotlin for Gradle - works in both cases.
But I would like to use Kotlin DSL for Gradle and apply the plugins via the legacy way, since this way I can apply plugins dynamically, i.e. under certain conditions.
In general, you can use apply false in the plugins DSL and call apply conditionally. Apply alone will NEVER work with Kotlin DSL, it only works with dynamic Groovy. Kotlin can work like Groovy if you also use the plugins DSL + apply false in it.
Example:
plugins {
kotlin("multiplatform") apply false // Applied conditionally later
}
For more detailed discussion of the problem check this.
Is there a way to leverage the new functions withSourcesJar() and withJavadocJar() for Android library projects? Currently when I try to use it I get:
> SourceSet with name 'main' not found.
With the latest Gradle version 6.0.1, there seems to be no way to use these new methods in Android library projects. Here’s why I believe that’s the case:
The two methods withJavadocJar() and withSourcesJar() on the java extension have the default main source set hardcoded, see here and here.
There are two methods with the same names (withJavadocJar() and withSourcesJar()) which can be used in feature variant declarations. However, it seems that Android Gradle builds don’t use feature variants, i.e., these methods can’t be used either.
The documentation states, that these come from the JavaPluginExtension - but not from Android DSL. So they can only be used in conjunction with apply plugin: "java" or apply plugin: "java-library", but not with apply plugin: "com.android.application", apply plugin: "com.android.library" and alike. The name of these tasks also suggest that it's common Java (*.jar) and not Android (*.aar). On Android, this would only make sense for a *.jar library, which uses pure Java features, but no Android features at all (which is limited in functionality).
In short, apply plugin: "java-library" would permit accessing these.
With Gradle 7.2 I "recreated" withJavadocJar and withSourcesJar using Gradle Kotlin DSL:
val sourceFiles = android.sourceSets.getByName("main").java.getSourceFiles()
tasks.register<Javadoc>("withJavadoc") {
isFailOnError = false
dependsOn(tasks.named("compileDebugSources"), tasks.named("compileReleaseSources"))
// add Android runtime classpath
android.bootClasspath.forEach { classpath += project.fileTree(it) }
// add classpath for all dependencies
android.libraryVariants.forEach { variant ->
variant.javaCompileProvider.get().classpath.files.forEach { file ->
classpath += project.fileTree(file)
}
}
source = sourceFiles
}
tasks.register<Jar>("withJavadocJar") {
archiveClassifier.set("javadoc")
dependsOn(tasks.named("withJavadoc"))
val destination = tasks.named<Javadoc>("withJavadoc").get().destinationDir
from(destination)
}
tasks.register<Jar>("withSourcesJar") {
archiveClassifier.set("sources")
from(sourceFiles)
}
Put this into your gradle.build.kts file and then run ./gradlew withJavadocJar and ./gradlew withSourcesJar (or use the tasks to create artifacts for publishing).
android.sourceSets.getByName("main").java.getSourceFiles() is the Android specific part to retrieve the "main" source files.
I've been trying to get the code coverage for my local unit tests and haven't been successful.
Here's a reference on what I mean by local unit tests.
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
To run my unit tests, I use the following gradle command.
./gradlew clean testDebugUnitTest
This task will run the unit tests but when I view the jacoco file that gets generated (testDebugUnitTest.ec) in "build/jacoco" folder, it always shows an empty coverage.
I've enabled the coverage in my build.gradle file as follows.
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
but that doesn't seem to help. Is there something that I am missing?
Note that if I run the local unit tests through Android Studio, everything works fine. I clicked on my "tests" module and click on "Run tests with coverage".
So, I found out the answer to my own question. Oddly enough, it looks like running "testDebugUnitTest" with the "testCoverageEnabled" flag set is the correct way to do it.
However, since apparently gradle's jacoco version is different than the jacoco version that is running in Android Studio and my CI system (Jenkins), it wasn't able to be viewed due to some backwards compatibility issue in jacoco.
To fix the issue, I set my jacoco version in gradle to the same one in my Android Studio (Intellij) and Jenkins.
jacoco {
toolVersion = '0.7.0.201403182114'
}
I put the code above in my build.gradle file.
I've had to solve the problem myself and I was actually expecting the default gradle plugin will have support for code coverage for local unit tests. Unfortunately, out of the box, there is no support for this, even on android gradle plugin version 3.0.1.
Fortunately, however, there is a simple third-party plugin we can use to generate jacoco test reports: gradle-android-junit-jacoco-plugin
To use it, you need to register this plugin's repository and classpath into your root-level build.gradle. Your build.gradle file might look different, but this is what worked for me:
buildscript {
repositories {
// ... there may be other repositories here
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
// ... other classpaths here too
classpath "gradle.plugin.com.vanniktech:gradle-android-junit-jacoco-plugin:0.11.0"
}
}
And to generate the report, one can simply do this:
./gradlew jacocoTestReportDebug
The output will be in one of your modules build folder, for example:
your-module/build/reports/coverage/debug/index.html
Note I verified this working on android gradle plugin 3.0.1.
For reference, my source is this answer from Niklas, creator of the plug-in: https://stackoverflow.com/a/33064500/390718
We use a company-wide gradle configuration which is applied to all our gradle projects.
Projects using this config might apply different types of plugins (specificially the plugins java or android & android-library). In order to get the sonarRunner plugin to automatically check the android projects, additional properties have to be applied which are not available for java projects.
Now to the question: How can additional sonarRunner (or other) properties be applied only to projects applying a specific (in this case "android" or "android-library") plugin?
What I have tried so far, but does not work as the AndroidPlugin property is not know in the preparation phase:
plugins.withType(AndroidPlugin) {
sonarRunner {
sonarProperties {
property "sonar.profile", "Android"
...
}
}
}
Sounds like the code is missing an import for the AndroidPlugin class. Alternatively, plugins.withId("android") can be used for current gradle versions or afterEvaluate { if (plugins.hasPlugin("android")) { ... } } for gradle 1.12 and earlier.
I am developing apps using Android Studio.
I was able to run the test code.
But, I do not know how to get code coverage in android studio.
I have already seen the following links.
Android Gradle Code Coverage
But I can't wait for update to v0.6 supporting emma.
Project configuration is as follows.
Main code
MyProject/AppName/src/main/java/mypackage/MyClass.java
Test code
MyProject/AppName/src/instrumentTest/java/mypackage/test/MyClassTest.java
Project configuration
MyProject
├─build.gradle
└─AppName
├─build.gradle
└─src
├─main
│ ├─java
│ │ └─mypackage
│ │ └─MyClass.java
│ ├─res
│ └─AndroidManifest.xml
└─instrumentTest
└─java
└─mypackage
└─test
└─MyClassTest.java
With the new Android Studio 1.2, you are able to run your unit tests and see the coverage all within the IDE.
First, you'll need to get your unit tests running in the IDE. (if you already can, then skip this step)
This guide and demo will help you.
Secondly, you'll need to create a JUnit Run configuration
Inside this configuraiton, you'll be able to choose
Test Kind: "All in Package"
Package: [the package where your tests reside, eg: "com.myapp.tests"]
Search for tests: Across Module Dependencies (could be diff for your
setup)
VM -options: -ea
Working Directory: [your project's directory]
Use classpath of mod: [select your module]
If you have any issue creating your JUnit Run Configuration, you should visit this guide for help.
Lastly, in the latest Android Studio, you should be able to run your JUnit-Run Configuration by clicking on the 'Run with Coverage' button.
In Android Studio 2.1.3 the is label Run Unit tests with Coverage where Unit test is the name of your test configuration as shown in the following screenshot:
There are so much answers showing how to apply jacoco plugin to Android studio project, which is outdated, and wasted me so much time to figure out the solution for recently Android studio(My Android Studio is version 2.1.2).
Jacoco plugin is built in for Android Studio gradle, what you need to do is just enable it like following:
buildTypes {
...
debug {
testCoverageEnabled true
}
}
After you do above, run unit test task
./gradlew testDebugUnitTest
Then create coverage files:
./gradlew createDebugCoverageReport
Coverage files will be created under <module>/build/reports/coverage/debug folder,include index.html, which you can open it with browser, and report.xml which you can use to get a report by jenkins jacoco plugin or other continues integration tools.
For those who got 0% coverage with jenkins jacoco plugin, be sure to use the right version.
quote from their site:
Unfortunately JaCoCo 0.7.5 breaks compatibility to previous binary
formats of the jacoco.exec files. The JaCoCo plugin up to version
1.0.19 is based on JaCoCo 0.7.4, thus you cannot use this version with projects which already use JaCoCo 0.7.5 or newer. JaCoCo plugin
starting with version 2.0.0 uses JaCoCo 0.7.5 and thus requires also
this version to be used in your projects. Please stick to JaCoCo
plugin 1.0.19 or lower if you still use JaCoCo 0.7.4 or lower
If you want to get your test coverage (for instrumented tests - When the 'Run the app with Coverage' is not enabled):
Put this into your top-level build.gradle:
buildscript{
ext.jacocoVersion = '0.8.2'
...
dependencies {
classpath "org.jacoco:org.jacoco.core:$jacocoVersion"
}
}
Into your app-level build.gradle:
...
apply plugin: 'jacoco'
jacoco {
toolVersion = "$jacocoVersion"
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = [
'**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*'
]
def debugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
def mainSrc = "$project.projectDir/src/main/kotlin"
sourceDirectories = files([mainSrc])
classDirectories = files([debugTree])
executionData = fileTree(dir: project.buildDir, includes: [
'jacoco/testDebugUnitTest.exec', 'outputs/code_coverage/debugAndroidTest/connected/**/*.ec'
])
}
android {
...
buildTypes {
debug {
testCoverageEnabled true
}
}
Then you should write your test, and tests have to passed. If you are sure, your tests passed, write that code into the terminal:
gradlew connectedCheck
It will run your tests.
If you did everything right, you should get a report file in
app -> build -> reports -> coverage.
You have to open the index.html file. (Right click on the file -> Open in Browser -> select a browser)
You should get something similar to this.
It's working in my project. Maybe there is a better and easier solution.
If I forgot something to write down here, pls write comment.
Enable testCoverage in your module build.gradle file
buildTypes {
debug {
testCoverageEnabled true
}
}
and then
Right click on the test -> java package and select Run Tests in Java with Coverage to run all tests with code coverage or right click on the particular test class and click Run SampleTest with Coverage
We use maven to build our app and cobertura for code coverage reporting
both are really easy to integrate
android maven integration:
http://www.vogella.com/tutorials/AndroidBuildMaven/article.html
Maven + Cobertura Code Coverage Example:
http://www.mkyong.com/qa/maven-cobertura-code-coverage-example/
I don't think you can see visual code coverage report inside Android Studio. But you could try Jacoco. You will need to integrate it in your build.gradle file. You can find the similar question & solution here
Have you tried using the Jacoco plugin for getting code coverage for your project? It is a good plugin giving you coverage based on your package or individual classes. I am not sure how you configure Jacoco to use with Gradle since i use Maven. Check the link: and see if it helps you
Android studio gradle has inbuilt Jacoco plugin which you can use to find code coverage. I have written as article to step by step configure jaococo to find code coverage for Espresso test case but you can use it for Robotium as well. check this out.
http://qaautomated.blogspot.in/2016/03/how-to-find-code-coverage-with-jacoco.html
You can just right click on the package you are curious about and select Run 'Tests in "package" with coverage'