在2019年使用Sonarqube和Jacoco评估Android应用程序代码质量


哈Ha!


我叫Artyom Dobrovinsky,我是FINCH的一名Android开发人员。


一次,在与一家公司的同事进行了几品脱后,该公司正在投放广告来销售MIG和蚊子,名为Igor,然后,我们开始讨论CI中的静态代码分析器(以及其他讨论内容)。 有人提出使用它们很酷的想法-但只有在对代码的逻辑可靠性有了信心之后。 换句话说,只有在编写完所有测试后,您才能考虑代码样式。


我决定听取我的同事的意见,并思考如何为简易应用程序计算灾难的规模。 观点落在Sonarqube和Jacoco身上。 将它们连接到hello-world项目的过程很基本。 将它们连接到细分为模块的Android项目中已经变得更加困难。 为了帮助那些有兴趣的人,写了这篇文章。


Habré已经对使用Sonarqube 教程进行了很好的翻译 -但是从2016年开始,那里已经过时了,没有kotlin,只是我发现所有buildType冗余的报告生成。


关于不熟悉图书馆的人的一些知识。


Sonarqube是一个开源平台,用于持续检查和衡量代码质量。 它使您能够跟踪一段时间内与技术债务的斗争(很高兴看到技术债务正在获胜,您对此无能为力)。 Sonar还监视重复的代码,潜在的漏洞以及功能的过度复杂性。


Jacoco是一个免费的库,用于计算Java项目的测试覆盖率。 但是有了Kotlin,我们将结识她的朋友。


如何连接Sonarqube和Jacoco


在根模块的build.gradle中,添加以下代码:


apply plugin: 'android.application' apply plugin: 'org.sonarqube' sonarqube { properties { property "sonar.host.url", "%url   sonarqube%" property "sonar.login", "%%" property "sonar.projectName", "% %" property "sonar.projectKey", "%  %" property "sonar.reportPath", "${project.buildDir}/sonarqube/test.exec" property "sonar.projectBaseDir", "$rootDir" property "sonar.sources", "." property "sonar.tests", "" property "sonar.coverage.exclusions", "**/src/androidTest/**, **/src/test/**" property "sonar.coverage.jacoco.xmlReportPaths", fileTree(include: ['*/*/jacoco*.xml'], dir: "$rootDir/app/build/reports/jacoco").collect() } } 

sonar.reportPath指示声纳应将报告放在何处以进行进一步分析。
sonar.projectBaseDir指定最初将在其中开始分析的文件夹; 在我们的例子中,这是$ rootDir-项目的根文件夹。
sonar.coverage.exclusions列出了用于计算覆盖率的例外,其中**是任何文件夹,*是任何文件名或分辨率。
sonar.sources是源文件夹。
sonar.tests在此处为空行,因此Sonarqube也可以分析测试。
sonar.coverage.exclusions我们从测试覆盖率分析中排除测试。
sonar.coverage.jacoco.xmlReportPaths使用collect()收集Jacoco报告以计算测试覆盖率。


要激活Jacoco,最好创建一个jacoco.gradle文件并在其中写入所有必要的逻辑。 这将有助于避免使另一个build.gradle混乱。


为了不在每个子项目的build.gradle中注册Jacoco,我们在子项目闭包中规定了其初始化。 在reportsDirPath for submodules中,指定根文件夹。 Sonar将在此获取Jacoco的所有报告。


 subprojects { apply plugin: 'jacoco' jacoco { toolVersion = '0.8.5' def reportsDirPath = "${project.rootDir}/app/build/reports/jacoco/${project.name}" reportsDir = file(reportsDirPath) } } 

在同一文件中,我们编写了一个配置Jacoco的函数。
这个功能很棒,所以我先带它-然后再解释其中发生了什么。


 def configureJacoco = { project -> def variantName = project.name project.tasks.create(name: "getJacocoReports", type: JacocoReport) { group = "Reporting" description = "Generate Jacoco coverage reports for the $variantName build." reports { html.enabled = true xml.enabled = true } def excludes = [ '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/AndroidManifest.xml', '**/*Test*.*', 'android/**/*.*', 'androidx/**/*.*', '**/*Fragment.*', '**/*Activity.*', '**/*Api.*', '**/injection/**/*.class', '**/ui/**/*.class', %  build- % ] def javaClasses = fileTree(dir: "${project.buildDir}/intermediates/javac", excludes: excludes) def kotlinClasses = fileTree(dir: "${project.buildDir}/tmp/kotlin-classes", excludes: excludes) classDirectories = files([javaClasses, kotlinClasses]) sourceDirectories = files([ "${project.projectDir}/src/main/java", "${project.projectDir}/src/main/kotlin", ]) executionData = files(fileTree(include: ['*.exec'], dir: "${project.buildDir}/jacoco").files) } } 

我们创建了getJacocoReports任务,即“报告”组。 报告将以html和xml格式提供。 将分析除excludes数组中包含的文件以外的所有文件。 除了生成的Androyd文件之外,我决定从分析中排除所有片段和活动,Retrofit接口,带有DI的程序包,自定义视图和库代码。
也许这个列表会随着时间而改变。


classDirectories指示在何处查找要分析的代码。 我们在此处同时包含java和kotlin文件。
sourceDirectories指定Jacoco在何处查找源文件。
executionData与Sonar一样,指示将在何处生成报告以计算覆盖率。


同样在jacoco.gradle中,您需要使用上述功能为所有模块添加其配置:


 allprojects { project -> configureJacoco(project) project.tasks.withType(Test) { enabled = true jacoco.includeNoLocationClasses = true } } 

还有一个用于收集生成的报告的任务:


 task getJacocoReports() { group = "Reporting" subprojects.forEach { subproject -> subproject.tasks.withType(JacocoReport).forEach { task -> dependsOn task } } } 

通过命令行运行Sonarqube


它的./gradlew % % && ./gradlew jacocoAggregateReports && ./gradlew sonarqube简单: ./gradlew % % && ./gradlew jacocoAggregateReports && ./gradlew sonarqube 。 命令通过&&运行,因为如果上一步没有成功,则应该中断执行。


上面的命令会发生什么:


  1. 首先,运行测试(同时我们在build文件夹中生成所有必需的文件)。
  2. 生成Jacoco报告。
  3. 发射Sonarqube。

接下来,您需要转到站点,使项目失败,然后查看灾难的规模。 项目页面显示最后检查的结果。


使用Sonarqube,项目状态的想法变得更加完整。 调整技术债务积压要比接受新手开发人员容易(在每个小问题中,Sonarqube都提出了为什么不接受这样写的论点-阅读这些说明可能非常有用),并且简单地说, 知识就是力量


就是这样,伙计们!


给读者的问题-您使用什么来分析代码和衡量测试覆盖率? 您一点都明白吗?

Source: https://habr.com/ru/post/zh-CN475784/


All Articles