【问题标题】:Gradle powermock codecoverage missedGradle powermock 代码覆盖丢失
【发布时间】:2018-02-08 03:17:32
【问题描述】:

当我在测试中使用 powermock 时,如何配置 gradle 以生成声纳的代码覆盖率?我发现 jacoco 不支持这一点。是否有任何其他代码覆盖插件可以与 powermock 一起使用?

【问题讨论】:

    标签: gradle sonarqube code-coverage powermock


    【解决方案1】:

    只要https://github.com/powermock/powermock/issues/727 不固定,您就可以尝试使用 JaCoCo 离线检测而不是运行中检测,这将使 PowerMock 与 JaCoCo 运行中检测兼容。

    或者,您可以使用不同的模拟框架,例如 e. G。 JMockit。据我所知,这与 JaCoCo 即时仪器兼容。

    【讨论】:

    • 我查看了 JMockit,但它是一个非常简单的模拟框架。我需要在测试类中模拟对象创建。 JMock 很难。即使是嘲笑具体课程也很难。从我发现 JMock 可以模拟接口的信息中。所以在我的测试中,我需要创建新接口并包装我的类。仅更改运行测试的代码太多。我正在使用离线仪器检查 JaCoCo,但在 gradle 中找不到示例。
    • 不要将 jMock 与 JMockit 混淆。 JMockit 可能是你能找到的最强大的模拟框架,到目前为止,我还没有发现 JMockit 无法实现的功能。
    • 很抱歉混淆了框架名称。当然,我的意思是 JMockit。仍然,JMockit 对我来说是不直观的。我不想只为测试编写额外的接口。并非所有我想模拟的东西都设计得当并且有界面。
    • 你不需要。 JMockit 可以轻松地模拟接口、类、静态方法、最终方法、地狱,甚至可以轻松模拟静态初始化块、构造函数和私有方法。您甚至不需要像许多模拟框架所需的那样创建模拟并将其手动注入到测试类中,但它“可以正常工作”。我假设您仍然将 jMock 与 JMockit 混淆。 JMockit 在网页上也有一个很棒的教程,它解释了几乎所有内容,并且是一个响应迅速且乐于助人的开发人员。
    【解决方案2】:

    我放弃使用 gradle 和 jacoco。现在我正在使用 maven + cobertura + powermock,一切都没有黑客攻击。为什么我使用maven?因为我找不到如何使用 gradle 在 cobertura 中生成 xml 代码覆盖率报告。

    【讨论】:

    • 在此询问并不会取消对 Google 的需求。一个简单的搜索显示为首次点击stackoverflow.com/questions/41370815/…,其中显示了带有 Gradle 的 Jacoco 离线检测。在github.com/stevesaliman/gradle-cobertura-plugin,您可以找到一个集成了 Cobertura 的 Gradle 插件。
    • 我在这里问之前发现了,但是这个解决方案不会产生xml格式的覆盖率。
    • 您是指 Jacoco 离线仪器还是 Cobertura?
    • 假设您的意思是 Cobertura,查看使用页面并搜索 XML 会有所帮助,这将显示 coverageFormats = [ <formats> ]: Tells the plugin what report formats should be used. Cobertura supports 'html' and 'xml'. The default is html.
    • 谢谢。我没找到。
    【解决方案3】:

    Jacoco Offline Instrumentation 是解决这个问题的方法。

    查看我的 gradle 构建文件

    Build and run tests:
    Linux:
    \$ ./gradlew
    Windows:
    \$ gradlew
    ------------------------------------------
    """
    
    apply plugin: 'java'
    apply plugin: 'org.sonarqube'
    apply plugin: 'jacoco'
    
    // Project group and version
    group 'com.abcd.jacocoTest'
    version '1.0.0'
    
    // JDK version source compatibility
    sourceCompatibility = 1.8
    
    // JDK version target compatibility
    targetCompatibility = 1.8
    
    configurations {
        jacocoAnt
        jacocoRuntime
    }
    
    task wrapper(type: Wrapper) {
        gradleVersion = "4.5.1"
    }
    
    defaultTasks 'clean', 'test'
    
    buildscript {
        repositories {
            maven { url "https://plugins.gradle.org/m2/" }
        }
    
        dependencies {
            classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2"
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
    
        jacocoAnt group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.1'
        jacocoAgent group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.1'
        testCompile group: 'junit', name: 'junit', version: '4.12'
        testCompile group: 'org.mockito', name: 'mockito-core', version: '2.8.9'
        testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.7.4'
        testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '1.7.4'
        testCompile group: 'org.powermock', name: 'powermock-api-easymock', version: '1.7.4'
    
    }
    
    test {
        testLogging {
            afterSuite { desc, result ->
                if (!desc.parent) { // will match the outermost suite
                    println "Unit Tests: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
                }
            }
        }
    
        jacoco {
            append = "false"
            destinationFile = file("$buildDir/reports/jacoco/jacoco-sonar/jacoco-coverage.exec")
        }
    }
    
    jacoco {
        toolVersion = "0.8.0"
    }
    
    jacocoTestReport {
        reports {
            html.destination file("${buildDir}/reports/jacoco/jacocoHtml")
        }
    }
    
    sonarqube {
        properties {
            property "sonar.projectName", 'JacocoTest'
            property "sonar.host.url", "http://localhost:9000"
            property "sonar.java.binaries", "${buildDir}/classes"
            property "sonar.java.libraries", "**/*.jar"
            property "sonar.dynamicAnalysis", "reuseReports"
            property "sonar.jacoco.reportPaths", "${buildDir}/reports/jacoco/jacoco-sonar/jacoco-coverage.exec"
        }
    }
    
    task instrument(dependsOn: ['classes']) {
        ext.outputDir = buildDir.path + '/reports/classes-instrumented'
        doLast {
            ant.taskdef(name: 'instrument',
                    classname: 'org.jacoco.ant.InstrumentTask',
                    classpath: configurations.jacocoAnt.asPath)
            ant.instrument(destdir: outputDir) {
                fileset(dir: sourceSets.main.output.classesDir)
            }
        }
    }
    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(instrument)) {
            tasks.withType(Test) {
                doFirst {
                    classpath = files(instrument.outputDir) + classpath + configurations.jacocoRuntime
                }
            }
        }
    }
    task report(dependsOn: ['instrument', 'test']) {
        doLast {
            ant.taskdef(name: 'report',
                    classname: 'org.jacoco.ant.ReportTask',
                    classpath: configurations.jacocoAnt.asPath)
            ant.report() {
                executiondata {
                    ant.file(file: buildDir.path + '/reports/jacoco/jacoco-sonar/jacoco-coverage.exec')
                }
                structure(name: 'Example') {
                    classfiles {
                        fileset(dir: sourceSets.main.output.classesDir)
                    }
                    sourcefiles {
                        fileset(dir: 'src/main/java')
                    }
                }
                html(destdir: buildDir.path + '/reports/jacoco')
            }
        }
    }
    

    此处报告任务将创建项目的离线检测文件。

    最后,执行 sonarqube 任务。 然后你可以看到powermocked类的覆盖范围也包括在内了。

    Execution command ./gradlew report sonarqube
    

    然后去看看你的声纳主机(localhost:9000)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-21
      • 1970-01-01
      • 2017-11-01
      • 2014-06-15
      • 2012-03-23
      相关资源
      最近更新 更多