Code coverage on Play! project

2.1k views Asked by At

I have a Play! project where I would like to add some code coverage information. So far I have tried JaCoCo and scct. The former has the problem that it is based on bytecode, hence it seems to give warning about missing tests for methods that are autogenerated by the Scala compiler, such as copy or canEqual. scct seems a better option, but in any case I get many errors during tests with both.

Let me stick with scct. I essentially get errors for every test that tries to connect to the database. Many of my tests load some fixtures into an H2 database in memory and then make some assertions. My Global.scala contains

override def onStart(app: Application) {
    SessionFactory.concreteFactory = Some(() => connection)

    def connection() = {
        Session.create(DB.getConnection()(app), new MySQLInnoDBAdapter)
    }
}

while the tests usually are enclosed in a block like

class MySpec extends Specification {
    def app = FakeApplication(additionalConfiguration = inMemoryDatabase())

    "The models" should {
        "be five" in running(app) {
            Fixtures.load()
            MyModels.all.size should be_==(5)
        }
    }
}

The line running(app) allows me to run a test in the context of a working application connected to an in-memory database, at least usually. But when I run code coverage tasks, such as scct coverage:doc, I get a lot of errors related to connecting to the database.

What is even more weird is that there are at least 4 different errors, like:

  • ObjectExistsException: Cache play already exists
  • SQLException: Attempting to obtain a connection from a pool that has already been shutdown
  • Configuration error [Cannot connect to database [default]]
  • No suitable driver found for jdbc:h2:mem:play-test--410454547

Why is that launching tests in the default configuration is able to connect to the database, while running in the context of scct (or JaCoCo) fails to initialize the cache and the db?

3

There are 3 answers

0
Roch On

You need to add sequential in the beginning of your Specification.

class MySpec extends Specification {
  sequential

  "MyApp" should {
  //...//
  }

}
1
sksamuel On

A better option for Scala code coverage is Scoverage which gives statement line coverage. https://github.com/scoverage/scalac-scoverage-plugin

Add to project/plugins.sbt:

addSbtPlugin("com.sksamuel.scoverage" % "sbt-scoverage" % "1.0.1")

Then run SBT with

sbt clean coverage test
2
Alex Varju On

specs2 tests run in parallel by default. Play disables parallel execution for the standard unit test configuration, but scct uses a different configuration so it doesn't know not to run in parallel.

Try adding this to your Build.scala:

.settings(parallelExecution in ScctPlugin.ScctTest := false)

Alternatively, you can add sequential to the beginning of your test classes to force all possible run configurations to run sequentially. I've got both in my files still, as I think I had some problems with the Build.scala solution at one point when I was using an early release candidate of Play.