定义了一些全局变量,如项目版本,springboot版本,sonar的账号密码等一些内容。
springbootVersion=2.3.2.RELEASE
projectVersion=1.0-SNAPSHOT
#sonarQube 配置
systemProp.sonar.host.url=http://192.168.16.173:9000
systemProp.sonar.login=账号
systemProp.sonar.password=密码
sonar.pdf.username=上传pdf文件账号
sonar.pdf.password=上传pdf文件密码
定义gradle的构建脚本内容,包含springboot,单元测试,jacoco插件,sonar插件,powerMock的依赖。
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://mvnrepository.com/artifact/" }
}
dependencies {
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1")
}
}
plugins{
id 'java'
}
apply plugin: "org.sonarqube"
apply from: "${rootDir}/jacoco.gradle"
sonarqube {
properties {
property "sonar.sourceEncoding", "UTF-8"
}
}
subprojects{
group = 'com.example'
sourceCompatibility = '1.8'
apply plugin: 'java'
//sonar扫描的路径
sonarqube {
properties {
property "sonar.sources", "src/main/java"
property "sonar.jacoco.reportPaths","${projectDir.path}/build/jacoco/tests.exec"
}
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
repositories {
mavenCentral()
maven {url "https://maven.aliyun.com/nexus/content/groups/public/"}
maven {url "http://192.168.9.39:8081/repository/maven-public/"}
}
dependencies {
//单元测试集成
testImplementation("org.springframework.boot:spring-boot-starter-test:${springbootVersion}") {
//exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
//powerMock依赖
testImplementation("org.powermock:powermock-api-mockito2:2.0.2")
testImplementation("org.powermock:powermock-module-junit4:2.0.2")
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
test {
useJUnitPlatform()
}
}
jacoco离线模式需要的一些自定义task内容。
apply plugin: 'java'
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
jcenter()
}
configurations {
jacoco
jacocoRuntime
}
dependencies {
jacoco group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.4', classifier: 'nodeps'
jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.4', classifier: 'runtime'
}
subprojects {
apply plugin: 'java'
sourceCompatibility = 1.8
configurations {
jacoco
jacocoRuntime
jacocoInstrumented
}
dependencies {
testImplementation 'junit:junit:4.12'
jacoco group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.4', classifier: 'nodeps'
jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.4', classifier: 'runtime'
}
task preprocessClassesForJacoco(dependsOn: ['classes']) {
ext.outputDir = buildDir.path + '/classes-instrumented'
doLast {
ant.taskdef(name: 'instrument',
classname: 'org.jacoco.ant.InstrumentTask',
classpath: configurations.jacoco.asPath)
ant.instrument(destdir: outputDir) {
fileset(dir: sourceSets.main.java.outputDir, includes: '**/*.class', erroronmissingdir: false)
}
}
}
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(preprocessClassesForJacoco)) {
tasks.withType(Test) {
doFirst {
systemProperty 'jacoco-agent.destfile', buildDir.path + '/jacoco/tests.exec'
classpath -= files(sourceSets.main.java.outputDir)
classpath += files(preprocessClassesForJacoco.outputDir) + configurations.jacocoRuntime
def modulesDependencies = moduleDependencies(project)
classpath -= files(modulesDependencies.jar.outputs.files)
classpath += files(modulesDependencies.jacocoInstrumentedJar.outputs.files)
}
}
}
}
task jacocoInstrumentedJar(type: Jar, dependsOn: [preprocessClassesForJacoco]) {
baseName "${project.name}-instrumented"
from preprocessClassesForJacoco.outputDir
}
test.dependsOn preprocessClassesForJacoco
test.dependsOn jacocoInstrumentedJar
artifacts {
jacocoInstrumented jacocoInstrumentedJar
}
}
def moduleDependencies(Project project) {
ConfigurationContainer configurations = project.configurations
Configuration configuration = configurations.compile
DomainObjectSet<ProjectDependency> projectDependencies = configuration.dependencies.withType ProjectDependency
def modules = []
projectDependencies.forEach {
modules += it.dependencyProject
modules += moduleDependencies(it.dependencyProject)
}
return modules
}
task report() {
doLast {
ant.taskdef(name: 'report',
classname: 'org.jacoco.ant.ReportTask',
classpath: configurations.jacoco.asPath)
ant.report() {
executiondata {
subprojects.buildDir.path.collect { file(it + '/jacoco/tests.exec') }.findAll { it.exists() }.each {
ant.file(file: it.path)
}
}
structure(name: 'Example') {
classfiles {
files(subprojects.sourceSets.main.output.classesDirs).each {
fileset(dir: it)
}
}
sourcefiles {
files(subprojects.sourceSets.main.java.srcDirs).each {
fileset(dir: it)
}
}
}
html(destdir: buildDir.path + '/reports/jacoco')
}
}
}
report.dependsOn += subprojects.test
原因:因为如果要使用powerMock进行mock静态方法的话,powerMock和jacoco在线模式一起使用会出现冲突,
具体冲突原因可以参考链接
所以,如果你要使用powerMock的某些强大的功能的话,那么你需要使用jacoco的离线模式
org.jacoco.ant 0.8.4
org.jacoco.agent 0.8.4
./gradlew clean report sonarqube
./gradlew clean build report sonarqube
执行完命令后,可以在build/reports文件夹下查看覆盖率
https://github.com/liushuyu1/jacoco_sonar_demo/blob/master/README.md