Code coverage for Scala integration tests with SCCT - scala

I'm running integration tests in Scala - these are found in the src/it/scala directory, and I've added the following to my build.sbt:
seq(Defaults.itSettings: _*)
However, when I run SCCT to calculate code coverage, the integration tests are not run. How can I make them be run?

I am using scct 0.3-SNAPSHOT / sbt 0.13
for mergin test + it:test try the following setting:
ScctPlugin.instrumentSettings ++ Defaults.itSettings ++ Seq(
resourceDirectory in ScctPlugin.ScctTest <<= (resourceDirectory in Test),
sources in ScctPlugin.ScctTest ++= (sources in IntegrationTest).value
)
this might get tricky if you have different resources

Related

scoverage: Combine Coverage from test and it:test

I splitted my Unit- and Integration-Tests with a Filter:
lazy val FunTest = config("it") extend Test
def funTestFilter(name: String): Boolean = name endsWith "Spec"
def unitTestFilter(name: String): Boolean = name endsWith "Test"
...
testOptions in Test := Seq(Tests.Filter(unitTestFilter)),
testOptions in FunTest := Seq(Tests.Filter(funTestFilter)),
...
So I can do something like that:
sbt clean coverage test dockerComposeUp it:test dockerComposeStop coverageReport
Sadly that kills all my Coverage, only the generated BuildInfo has a Coverage.
Using only sbt clean coverage test coverageReport or sbt clean coverage it:test coverageReport work as expected.
The whole project can be found here: https://github.com/pme123/play-binding-form
scoverage Version: 1.5.1
SBT supports incremental compilation, but Scoverage does not support it. Scoverage clears instrumentation information before compilation starts and starts instrumentation process from scratch every time. Compilation of a subset of all classes with Scoverage enabled will result in wrong coverage reports.
In this case sbt-buldinfo plugin is enabled in server module. It registers source generator, which is executed before every compilation and generates server/target/scala_2.12/src_managed/main/sbt-buildinfo/BuildInfo.scala file.
SBT BuildInfo plugin is smart enough to regenerate this file only when its content changes, but since BuildInfoOption.BuildTime is included in buildInfoOptions setting,
this file is regeneraged before every compilation.
When it comes to compilation process, compiler finds one modified file (BuildInfo.scala) every time and starts incremental compilation of this one file. Scoverage clears its previous instrumentation information and saves only information about BuildInfo.scala file.
In case of execution like sbt clean coverage test dockerComposeUp it:test dockerComposeStop coverageReport the first compilation process is part of test task, and the second one it:test task. That's why there is no problem, when they are used separately.
Docker has nothing to do with our problem.
To fix the problem you have to prevent from BuildInfo.scala file regeneration on every compilation, at least when coverage is enabled.
I did it by modifying project/Settings.scala file in this way:
private lazy val buildInfoSettings = Seq(
buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
buildInfoOptions ++= { if (coverageEnabled.value) Seq() else Seq(BuildInfoOption.BuildTime) }, // <-- this line was changed
buildInfoOptions += BuildInfoOption.ToJson,
buildInfoPackage := "pme123.adapters.version"
)
buildInfoOptions does not include BuildTime option when coverage is turned on.
It doesn't look elegeant, but it works. You can probably find better way.
instead of having different buildinfo objects depending on the phase, which could lead to compilation errors, you can use your own build time.
lazy val buildTime: SettingKey[String] = SettingKey[String]("buildTime", "time of build")
ThisBuild / buildTime := ZonedDateTime.now(ZoneOffset.UTC).toString
buildInfoKeys :=
Seq[BuildInfoKey](
name,
version,
scalaVersion,
sbtVersion,
buildTime
)
This should resolve this issue.
I have this configuration in a project of mine because I wanted a better control over the way the date is formatted, and I don't have the same issue

How to execute Main-Class as part of compile in SBT

I wanted to execute a task as part of SBT compile, I tried runMain in compile but it is not executing the main class that I am providing. Below is how task looks like in build.sbt
lazy val scalaGeneratorPlugin = Project("scala-generator", file("scala-generator"))
.settings(
libraryDependencies += "org.freemarker" % "freemarker" % "2.3.23",
runMain in compile := Some("com.my.MyMainClass")
)
I am running following command:
sbt scala-generator/compile
Although it gives me success message, it does not execute my MainClass
I am copying laughedelic's answer in comment here:
I think you should use source generation in sbt for that, i.e. there should be different compilation stages.

How to use SBT to run ScalaTest tests against a fat jar?

I have a simple SBT project, consisting of some Scala code in src/main/scala and some test code in src/test/scala. I use the sbt-assembly plugin to create a fat jar for deployment onto remote systems. The fat jar includes all the dependencies of the Scala project, including the Scala runtime itself. This all works great.
Now I'm trying to figure out a way I can run the Scala tests against the fat jar. I tried the obvious thing, creating a new config extending the Test config and modifying the dependencyClasspath to be the fat JAR instead of the default value, however this fails because (I assume because) the Scala runtime is included in the fat jar and collides somehow with the already-loaded Scala runtime.
My solution right now works but it has serious drawbacks. I just use Fork.java to invoke Java on the org.scalatest.tools.Runner runner with a classpath set to include the test code and the fat jar and all of the test dependencies. The downside is that none of the SBT test richness works, there's no testQuick, there's not testOnly, and the test failure reporting is on stdout.
My question boils down to this: how does one use SBT's test commands to run tests when those tests are dependent not on their corresponding SBT compile output, but on a fat JAR file which itself includes all the Scala runtimes?
This is what I landed on (for specs2, but can be adapted). This is basically what you said was your Fork solution, but I figured I'd leave this here in case someone wanted to know what that might be. Unfortunately I don't think you can run this "officially" as a SBT test runner. I should also add that you still want Fork.java even though this is Scala, because Fork.scala depends on a runner class that I don't seem to have.
test.sbt (or build.sbt, if you want to put a bunch of stuff there - SBT reads all .sbt files in the root if you want to organize):
// Set up configuration for building a test assembly
Test / assembly / assemblyJarName := s"${name.value}-test-${version.value}.jar"
Test / assembly / assemblyMergeStrategy := (assembly / assemblyMergeStrategy).value
Test / assembly / assemblyOption := (assembly / assemblyOption).value
Test / assembly / assemblyShadeRules := (assembly / assemblyShadeRules).value
Test / assembly / mainClass := Some("org.specs2.runner.files")
Test / test := {
(Test / assembly).value
val assembledFile: String = (Test / assembly / assemblyOutputPath).value.getAbsolutePath
val minimalClasspath: Seq[String] = (Test / assembly / fullClasspath).value
.filter(_.metadata.get(moduleID.key).get.organization.matches("^(org\\.(scala-lang|slf4j)|log4j).*"))
.map(_.data.getAbsolutePath)
val runClass: String = (Test / assembly / mainClass).value.get
val classPath: Seq[String] = Seq(assembledFile) ++ minimalClasspath
val args: Seq[String] = Seq("-cp", classPath.mkString(":"), runClass)
val exitCode = Fork.java((Test / assembly / forkOptions).value, args)
if (exitCode != 0) {
throw new TestsFailedException()
}
}
Test / assembly / test := {}
Change in build.sbt:
lazy val root = (project in file("."))
.settings(/* your original settings are here */)
.settings(inConfig(Test)(baseAssemblySettings): _*) // enable assembling in test

How to generate code coverage report in multi project builds using scct?

I am working on a multi project build. I have followed same instructions, as mentioned here http://mtkopone.github.io/scct/, to generate code coverage report.
I am able to see this message scct: [testProject] Saving coverage data. on console while running sbt scct:test. But can't see coverage report in this folder
$childProjectDir/target/scala_/coverage-report/
Here is some source code of build.scala
lazy val root = Project("platform3", file("."))
.settings(ScctPlugin.mergeReportSettings: _*)
.aggregate(
testProject
)
.settings(basicSettings: _*)
lazy val testProject = Project("testProject", file("testProject"))
.dependsOn(testUtil)
.settings(noPublishing: _*)
.settings(libraryDependencies ++= Seq(
akkaKernel,
akkaSlf4j,
jacksonScala,
jodaTime,
prettyTime,
logback,
sprayCan,
sprayRouting,
specs2
))
.settings(ScctPlugin.instrumentSettings: _*)
The dependency, which I am using
// Scct Plugin
addSbtPlugin("com.sqality.scct" %% "sbt-scct" % "0.3")
Can anyone help me to resolve this? Thanks in advance.
Ayush
SCCT is obsolete, use Scoverage instead. Check out my working example of a multi-module SBT project which creates coverage reports for individual projects.
https://github.com/RadoBuransky/sonar-scoverage-plugin/tree/master/samples/sbt/multi-module

Configuring junitxml output for specs2 tests in sbt 0.10

How do I configure sbt 0.10 to use the junitxml option with specs2?
The specs2 documentation says this is the way to do it using sbt 0.7.x:
override def testOptions = super.testOptions ++ Seq(TestArgument("junitxml"))
How do I say the same thing in sbt 0.10?
FYI, I found that when running Specs2 tests with juntxml SBT fails to fail when the tests fail. Adding "console" as another argument gets a build failure like you'd expect. I suspect this is some interaction between the console reporter and sbt's test driver.
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "junitxml", "console")
This is described here in the SBT documentation:
testOptions in Test += Tests.Argument("junitxml")
And if you want to specify this option specifically for specs2:
testOptions in Test += Tests.Argument(TestFrameworks.Specs2, "junitxml")