Search code examples
scalajacocojacoco-maven-plugin

Jacoco is analysing class twice and failing


I currently have this configuration for JaCoCo in my pom.xml:

<plugin> 
            <!-- Maven JaCoCo Plugin configuration for Code Coverage Report -->
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <inherited>true</inherited>
            <configuration>
                <excludes>
                    <exclude>**/*Test.class</exclude>
                </excludes>
            </configuration>

When I run mvn clean verify site, I get a failed build, based in this warning (and important thing: I have only 1 class, SayHello.scala):

Analyzed bundle 'dummy-project' with 2 classes
[WARNING] Rule violated for bundle dummy-project: classes missed count is 1, but expected maximum is 0
Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.5:check (default-check) on project dummy-project: Coverage checks have not been met. See log for details.

And finally, when I check the report, it's analysing the same class (the only difference is the extra "." in the second line), failing in one of them:

enter image description here

Update

SayHello.scala

package com.dummy

object SayHello {

def sayIt: String = "hello, world"

}

SayHelloTest.scala

package com.dummy

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class SayHelloTest extends AnyFunSuite with Matchers {

test("SayHello says hello") {
  SayHello.sayIt shouldBe "hello, world"

}

}

Anyone had a similar issue? Thank you.


Solution

  • JaCoCo analyzes .class files, not source files. The Scala compiler may produce multiple .class files from a single source file. Your SayHello.scala class most likely contains a companion object. An object is always compiled to a class of the same name with $ at the end, which implements the companion object singleton at the bytecode level. If you go to your target/classes directory, you'll most likely see those two files there - SayHello.class and SayHello$.class.

    Two records in the JaCoCo report correspond to those two class files. The dot at the end instead of a $ is most likely a jacoco report rendering issue.

    To skip the companion object class from analyzing, just add it to your exclusion list:

    <configuration>
      <excludes>
        <exclude>**/*Test.class</exclude>
        <exclude>**/*$.class</exclude>
      </excludes>
    </configuration>
    

    However, it seems that coverage of the methods in the companion object is attributed to SayHello$.class, not SayHello.class, so by removing the $ class from the list, you essentially lose the coverage.

    I'm not aware of any workarounds for the Maven+JaCoCo setup, apparently the jacoco-maven-plugin is not really Scala-aware. However, the sbt plugin appears to have worked around these issues, see e.g. https://blog.developer.atlassian.com/using-jacoco-a-code-coverage-tool-for-scala/

    If switching to sbt is not an option, you could take a look at some Scala-specific code coverage tools, like scoverage, which also has a maven plugin.