From the jacoco
tag, it looks like you're using Jacoco to generate coverage data for sonarqube to report.
Jacoco doesn't understand Scala, so it just sees your case class
as a JVM class. A Scala case class
has a lot of functionality that's synthesized by the compiler: to jacoco, that functionality counts for test coverage.
Most notably, the compiler synthesizes implementations for
equals
toString
hashCode
copy
These implementations are battle-tested (and tested in CI by the Scala compiler team, a large portion of which is employed by my employer), so there's probably not much value in you testing them. Accordingly, it's generally not recommended to use jacoco with Scala codebases, at least if you're using lots of case class
es and/or have a coverage requirement that would force you to test the synthetic functionality (something like scoverage
will be aware of what a case class
is).
If for whatever reason you absolutely have to get the coverage number for your case classes up, a test like this should help:
// test equals method
val bill = Person("Bill")
val ted = Person("Ted")
assert(bill == bill)
assert(bill != ted)
assert(bill != new AnyRef)
// test hashCode
assert(bill.hashCode == Person("Bill").hashCode)
// might be very unlucky if "Bill" and "Ted" hash the same, in which case this adventure is kinda bogus
assert(bill.hashCode != ted.hashCode)
// alternatively (only works since this is a single-field case class
assert((bill.name.hashCode == ted.name.hashCode) || (bill.hashCode != ted.hashCode))
// test toString
assert(bill.toString.startsWith("Person("))
// test copy (repeat this for all permutations of fields)
assert(bill.copy().name == bill.name)
assert(bill.copy(name = "Rufus").name == "Rufus")
You might have to look at the generated bytecode to find other methods you can test; likewise, the synthetic methods should be able to be decompiled into Java so you can get an idea of what the branches are. It's possible that things like modular shifts in hashCode
get interpreted as conditions, in which case you may need to experiment with the magic values required to satisfy the coverage metric.
As mentioned above, this effort to satisfy the broken coverage metric is basically wasted. I would recommend including a comment in these tests like:
// included solely to satisfy code coverage: these methods are synthesized by the compiler
(you can make them as passive-aggressive as you like :) )
For branch coverage (which is what I think is meant by condition?), it is possible that some branches cannot be triggered in idiomatic Scala.