6

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?

Michael Celey
  • 12,645
  • 6
  • 57
  • 62
Andrea
  • 20,253
  • 23
  • 114
  • 183
  • By the way, one thing I have always seen as suspect is the fact that I declare the application to use a `MySqlInnoDBAdapter`, but tests run on an in-memory H2 instance. Somehow the magic must happen in `FaekApplication`, but I wonder whether this has anything to do with the issue at hand – Andrea Jan 28 '13 at 10:24

3 Answers3

1

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.

Alex Varju
  • 2,922
  • 3
  • 24
  • 22
  • 1
    Thank you. I already had this configuration for JaCoCo, but it seems this is not the root cause of the problem. As far as I can tell, all errors I was getting are still there. :-( – Andrea Jan 28 '13 at 10:21
  • If you run a target like `play debug coverage:doc`, can you attach a debugger with a breakpoint in your `Global.scala` to see if it is being hit multiple times in parallel? – Alex Varju Jan 30 '13 at 00:46
1

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
sksamuel
  • 16,154
  • 8
  • 60
  • 108
  • How can we make this work for play framework based apps? It is instrumenting all the generated routes files, which is not the primary interest of the play application tests. – Santhosh Gandhe Nov 15 '16 at 01:45
0

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

class MySpec extends Specification {
  sequential

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

}
Roch
  • 21,741
  • 29
  • 77
  • 120