Below is my Build.scala file
There is no error in test, but the cleanup hook is not executed after test
what is the issue?
import play.Project._
import sbt._
import sbt.Keys._
object AppBuild extends Build {
val appName = "test"
val appVersion = "1.0"
val dependencies = Seq(
"org.scalatest" % "scalatest_2.10" % "2.0.RC1"
)
val main = play.Project(
appName, appVersion,
dependencies,
settings = Defaults.defaultSettings
)
.settings(
scalaVersion := "2.10.1",
testOptions in Test += Tests.Cleanup (
() => println("Cleanup")
)
)
}
testOptions in Test += Tests.Cleanup
does not work with forked test runs as mentioned in another Stackoverflow answer.
But there are workarounds:
Set fork to false
This is simple but may slow down your tests because they won't be executed in parallel.
sbt.Keys.fork in Test := false
Use the test framework
For example http://doc.scalatest.org/1.9.2/index.html#org.scalatest.BeforeAndAfterAll with the protected method afterAll()
Override the test task
My favorite.
test in Test ~= { testTask =>
val result = testTask
println("Cleanup")
result
}
Related
Below is a Scala test of websocket:
import java.util.function.Consumer
import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.test.{Helpers, TestServer, WsTestClient}
import scala.compat.java8.FutureConverters
import scala.concurrent.Await
import scala.concurrent.duration._
import org.scalatestplus.play._
class SocketTest extends PlaySpec with ScalaFutures {
"HomeController" should {
"reject a websocket flow if the origin is set incorrectly" in WsTestClient.withClient { client =>
// Pick a non standard port that will fail the (somewhat contrived) origin check...
lazy val port: Int = 31337
val app = new GuiceApplicationBuilder().build()
Helpers.running(TestServer(port, app)) {
val myPublicAddress = s"localhost:$port"
val serverURL = s"ws://$myPublicAddress/ws"
val asyncHttpClient: AsyncHttpClient = client.underlying[AsyncHttpClient]
val webSocketClient = new WebSocketClient(asyncHttpClient)
try {
val origin = "ws://example.com/ws"
val consumer: Consumer[String] = new Consumer[String] {
override def accept(message: String): Unit = println(message)
}
val listener = new WebSocketClient.LoggingListener(consumer)
val completionStage = webSocketClient.call(serverURL, origin, listener)
val f = FutureConverters.toScala(completionStage)
Await.result(f, atMost = 1000.millis)
listener.getThrowable mustBe a[IllegalStateException]
} catch {
case e: IllegalStateException =>
e mustBe an[IllegalStateException]
case e: java.util.concurrent.ExecutionException =>
val foo = e.getCause
foo mustBe an[IllegalStateException]
}
}
}
}
}
But compile is failing on line import org.scalatestplus.play._ with error :
Cannot resolve symbol scalatestplus
From https://www.playframework.com/documentation/2.8.x/ScalaTestingWithScalaTest I have added scalatest and play to build:
build.sbt:
name := "testproject"
version := "1.0"
lazy val `testproject` = (project in file(".")).enablePlugins(PlayScala)
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
resolvers += "Akka Snapshot Repository" at "https://repo.akka.io/snapshots/"
scalaVersion := "2.12.2"
libraryDependencies ++= Seq( jdbc , ehcache , ws , guice , specs2 % Test)
// https://mvnrepository.com/artifact/com.typesafe.scala-logging/scala-logging
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2"
libraryDependencies ++= Seq(
"org.scalatestplus.play" %% "scalatestplus-play" % "3.0.0" % "test"
)
unmanagedResourceDirectories in Test <+= baseDirectory ( _ /"target/web/public/test" )
I've tried rebuilding the project and module in IntelliJ "build" option and "Build Option" when I right click on build.sbt but the import is not found.
sbt dist from Intellij "sbt shell" then File -> "Invalidate caches" with restart of IntelliJ seems to fix the issue
:Invalidate caches screenshot
There is a great sbt plugin sbt-dependency-graph, which provides a dependencyTree task to show the dependencies.
I want to write a sbt plugin which depends on it, but always fails.
build.sbt
sbtPlugin := true
name := "my-sbt-plugin-depends-on-another"
version := "0.1.2.1"
organization := "test20140913"
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5")
src/main/scala/MySbtPlugin.scala
import sbt._
object MySbtPlugin extends AutoPlugin {
object autoImport {
lazy val hello = taskKey[Unit]("hello task from my plugin")
lazy val hello2 = taskKey[Unit]("hello task from my plugin2")
}
import autoImport._
override def trigger = allRequirements
override def requires = plugins.JvmPlugin
val helloSetting = hello := println("Hello from my plugin")
val helloSetting2 = hello2 := {
println("hello2, task result from another plugins:")
println(net.virtualvoid.sbt.graph.Plugin.dependencyTree.value)
println("=========================================")
}
override def projectSettings = Seq(
helloSetting, helloSetting2
)
}
Then I published it to local, and use it in another project:
build.sbt
name := "sbt--plugin-test"
version := "1.0"
scalaVersion := "2.11.6"
net.virtualvoid.sbt.graph.Plugin.graphSettings
project/plugins.scala
logLevel := Level.Info
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5")
addSbtPlugin("test20140913" % "my-sbt-plugin-depends-on-another" % "0.1.2.1")
When I run sbt on the later project, it reports:
Reference to undefined setting:
*:dependencyTree from *:hello2 (/Users/twer/workspace/my-sbt-plugin-depends-on-another/src/main/scala/test20140913/MySbtPlugin.scala:38)
Did you mean provided:dependencyTree ?
at sbt.Init$class.Uninitialized(Settings.scala:262)
at sbt.Def$.Uninitialized(Def.scala:10)
at sbt.Init$class.delegate(Settings.scala:188)
at sbt.Def$.delegate(Def.scala:10)
Where is wrong?
PS: The plugin code is here: https://github.com/freewind/my-sbt-plugin-depends-on-another
dependencyTree is only defined for specific configurations (well all of them), but it automatically delegates to Compile in the shell.
Try defining hello2 like so:
val helloSetting2 = hello2 := {
println("hello2, task result from another plugins:")
import net.virtualvoid.sbt.graph.Plugin.dependencyTree
println((dependencyTree in Compile).value)
println("=========================================")
}
I am trying to use the sbt-jasmine-plugin based on and referring to http://perevillega.com/post/2013/01/26/26/executing-jasmine-tests-in-play-204/. However after all configuration done and errors fixed, play test runs successfully but without executing any testcases.
Logs:
[info] running jasmine...
See https://github.com/jrburke/r.js for usage.
[ Envjs/1.6 (Rhino; U; Mac OS X x86_64 10.9.2; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13 ]
JQMIGRATE: Logging is active
Passed: 0
Failed: 0
Total : 0
Build.scala:
import sbt._
import Keys._
import play.Project._
import com.gu.SbtJasminePlugin._
object ApplicationBuild extends Build {
val appName = "webapp"
val appVersion = "1.0-SNAPSHOT"
// Project dependencies
val appDependencies = Seq(
javaCore,
javaJdbc,
javaEbean,
anorm,
javaJpa,
filters,
jdbc
)
lazy val main = play.Project(appName, appVersion, appDependencies)
.settings(jasmineSettings : _*)
.settings(
appJsDir <+= baseDirectory / "public/javascripts/app",
appJsLibDir <+= baseDirectory / "public/javascripts/vendor",
jasmineTestDir <+= baseDirectory / "test/js",
jasmineConfFile <+= baseDirectory / "test/jasmineDependencies.js",
(test in Test) <<= (test in Test) dependsOn (jasmine)
)
}
Plugin.scala:
import sbt._
object Plugins extends Build {
lazy val plugins = Project("plugins", file("."))
.dependsOn(uri("https://github.com/guardian/sbt-jasmine-plugin.git#0.7"))
}
Dependency file:
// Dependencies for the unit test via Jasmine
EnvJasmine.loadGlobal(EnvJasmine.libDir + "/../jquery-1.7.1.min.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "jquery-ui.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "jquery.tmpl.min.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "jquery-migrate-1.2.1.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "/angular/1.2.0rc1/angular.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "/angular/1.2.0rc1/angular-resource.min.js");
sample testSpec.js:
describe('Hello world', function() {
it('says hello', function() {
expect(helloWorld()).toEqual("Hello world!");
});
});
the folder structure for test is: webapp/test/js/specs/
Not sure where i am going wrong.
Finally i figured this out. It relates to the name of the test file. I had it earlier as testSpec.js and now i renamed it to test.spec.js. This time with "play test" i am able to execute the test case. i was thinking it will run all the cases in the test directory that was specified but not sure of it expects a certain file name format.
My goal is to integrate jacoco into my play 2.2.0 project.
Different guides on the web I tried to follow mostly added to confusion not to closing in on the goal.
Adding to confusion
Most guides assume the existance of an build.sbt
which as it seems as been superseded by an build.scala with a different
There is a jacoco4sbt and a regular jacoco
which one is most appropiate for use with scala play framework 2
Current state
in plugins.sbt added
addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.2")
in build.scala added
import de.johoop.jacoco4sbt.JacocoPlugin._
lazy val jacoco_settings = Defaults.defaultSettings ++ Seq(jacoco.settings: _*)
With these changes i don't get an "jacoco" task in sbt nor in the play console.
What are the appropriate steps to get this working?
Update
As requested the content of the build.scala
import com.typesafe.sbt.SbtNativePackager._
import com.typesafe.sbt.SbtScalariform._
import play.Project._
import sbt.Keys._
import sbt._
import sbtbuildinfo.Plugin._
import de.johoop.jacoco4sbt.JacocoPlugin._
object BuildSettings {
val buildOrganization = "XXXXX"
val buildVersion = "0.1"
val buildScalaVersion = "2.10.2"
val envConfig = "-Dsbt.log.format=false -Dconfig.file=" + Option(System.getProperty("env.config")).getOrElse("local.application")
scalacOptions ++= Seq("-encoding", "UTF-8", "-deprecation", "-unchecked", "-feature")
javaOptions += envConfig
val buildSettings = Defaults.defaultSettings ++ Seq (
organization := buildOrganization,
version := buildVersion,
scalaVersion := buildScalaVersion
)
}
object Resolvers {
val remoteRepoUrl = "XXXXXXXXXXXX" at "http://nexus.cXXXXX/content/repositories/snapshots/"
val publishRepoUrl = "XXXXXXXXXXXX" at "http://nexus.ciXXXXXXXXXXXXXXXX/content/repositories/snapshots/"
}
object Dependencies {
val ods = "XXXXXXXXX" % "XXXXXX-ws" % "2.2.1-SNAPSHOT"
val scalatest = "org.scalatest" %% "scalatest" % "2.0.M8" % "test"
val mockito = "org.mockito" % "mockito-all" % "1.9.5" % "test"
}
object ApplicationBuild extends Build {
import BuildSettings._
import Dependencies._
import Resolvers._
// Sub-project specific dependencies
val commonDeps = Seq(
ods,
scalatest,
mockito
)
//val bN = settingKey[Int]("current build Number")
val gitHeadCommitSha = settingKey[String]("current git commit SHA")
val release = settingKey[Boolean]("Release")
lazy val jacoco_settings = Defaults.defaultSettings ++ Seq(jacoco.settings: _*)
lazy val nemo = play.Project(
"nemo",
path = file("."),
settings = Defaults.defaultSettings ++ buildSettings ++
Seq(libraryDependencies ++= commonDeps) ++
Seq(scalariformSettings: _*) ++
Seq(playScalaSettings: _*) ++
buildInfoSettings ++
jacoco_settings ++
Seq(
sourceGenerators in Compile <+= buildInfo,
buildInfoKeys ++= Seq[BuildInfoKey](
resolvers,
libraryDependencies in Test,
buildInfoBuildNumber,
BuildInfoKey.map(name) { case (k, v) => "project" + k.capitalize -> v.capitalize },
"envConfig" -> envConfig, // computed at project load time
BuildInfoKey.action("buildTime") {
System.currentTimeMillis
} // re-computed each time at compile
),
buildInfoPackage := "com.springer.nemo"
) ++
Seq(resolvers += remoteRepoUrl) ++
Seq(mappings in Universal ++= Seq(
file("ops/rpm/start-server.sh") -> "start-server.sh",
file("ops/rpm/stop-server.sh") -> "stop-server.sh"
))
).settings(version <<= version in ThisBuild)
lazy val nemoPackaging = Project(
"nemoPackaging",
file("nemoPackaging"),
settings = Defaults.defaultSettings ++Seq(Packaging.settings:_*)
)
def publishSettings =
Seq(
publishTo := Option(publishRepoUrl),
credentials += Credentials(
"Repo", "http://mycompany.com/repo", "admin", "admin123"))
}
Note: jacoco is running with this but does not pick up our tests. Output:
jacoco:cover
[info] Compiling 1 Scala source to /home/schl14/work/nemo/target/scala-2.10/classes...
[info] ScalaTest
[info] Run completed in 13 milliseconds.
[info] Total number of tests run: 0
[info] Suites: completed 0, aborted 0
[info] Tests: succeeded 0, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] No tests to run for nemo/jacoco:test
I solved it by doing this.
Add the following to plugins.sbt
addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.2")
In build.scala i added a new import
import de.johoop.jacoco4sbt.JacocoPlugin._
and added jacoco to the config section like this
lazy val xyz = play.Project(
"xyz",
path = file("."),
settings = Defaults.defaultSettings
jacoco.settings ++ //this is the important part.
).settings(parallelExecution in jacoco.Config := false) //not mandatory but needed in `most cases as most test can not be run in parallel`
After these steps jacoco:cover was available in the sbt and play console and also discovers our tests.
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
To measure the code coverage of Java code jacoco4sbt is the best fit.
Add to project/plugins.sbt:
addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.2")
Add at the end of build.sbt:
jacoco.settings
Then run in the terminal:
//or just the sbt command and then use your browser
sbt jacoco:cover && /usr/bin/x-www-browser target/scala-2.10/jacoco/html/index.html
Scala code coverage can also be determined by SCCT.
Add to project/plugins.sbt:
addSbtPlugin("com.github.scct" % "sbt-scct" % "0.2.1")
Add at the end of build.sbt:
ScctPlugin.instrumentSettings
And then to see the coverage:
sbt scct:test && /usr/bin/x-www-browser target/scala_2.10/coverage-report/index.html
Maybe you get the error
Please either restart the browser with --allow-file-access-from-files
or use a different browser.
Maybe you use chrome and the security settings forbid dynamic actions on local files. You can open the page with firefox or use python -m SimpleHTTPServer 8000 to bind it to the http protokoll and open http://localhost:8000/target/scala-2.10/coverage-report/ .
Inspiration which generated classes should be excluded from the report can you find on the mailing list.
My test projects are on GitHub.
For my multi-project build, I'm trying to create a verify task that just results in scct:test and then scalastyle being executed in order. I would like scct:test to execute for all the subprojects, but not the top-level project. (If it executes for the top-level project, I get "timed out waiting for coverage report" from scct, since there's no source and no tests in that project.) What I had thought to do was to create verify as a task with dependencies on scct:test and scalastyle. This has turned out to be fairly baroque. Here is my Build.scala from my top-level project/ directory:
object MyBuild extends Build {
val verifyTask = TaskKey[Unit]("verify", "Compiles, runs tests via scct:test and then runs scalastyle")
val scctTestTask = (test in ScctPlugin.Scct).scopedKey
val scalastyleTask = PluginKeys.scalastyleTarget.scopedKey
lazy val root = Project("rootProject",
file("."),
settings = Defaults.defaultSettings ++
ScalastylePlugin.Settings ++
ScctPlugin.instrumentSettings ++
ScctPlugin.mergeReportSettings ++
Seq(
verifyTask in Global := {},
verifyTask <<= verifyTask.dependsOn(scctTestTask, scalastyleTask)
)
) aggregate(lift_webapp, selenium_tests)
lazy val subproject_1 = Project(id = "subproject_1", base = file("subproject_1"))
lazy val subproject_2 = Project(id = "subproject_2", base = file("subproject_2"))
}
However, the verify task only seems to exist for the root project; when I run it I don't see the same task being run in the subprojects. This is exactly the opposite of what I want; I'd like to issue sbt verify and have scct:test and scalastyle run in each of the subprojects but not in the top-level project. How might I go about doing that?
solution 1: define verifyTask in subprojects
First thing to note is that if you want some task (verify, test, etc) to run in some projects, you need to define them scoped to the subprojects. So in your case, the most straightforward thing to do this is to define verifyTask in subproject_1 and subproject_2.
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.4"
lazy val verify = taskKey[Unit]("verify")
def verifySettings = Seq(
skip in verify := false,
verify := (Def.taskDyn {
val sk = (skip in verify).value
if (sk) Def.task { println("skipping verify...") }
else (test in Test)
}).value
)
lazy val root = (project in file("."))
.aggregate(sub1, sub2)
.settings(
verifySettings,
scalaVersion in ThisBuild := "2.12.4",
skip in verify := true
)
lazy val sub1 = (project in file("sub1"))
.settings(
verifySettings,
libraryDependencies += scalaTest % Test
)
lazy val sub2 = (project in file("sub2"))
.settings(
verifySettings,
libraryDependencies += scalaTest % Test
)
solution 2: ScopeFilter
There was a recent Reddit thread that mentioned this question, so I'll post what I've done there.
If you want to manually aggregate on some subprojects, there's also a technique called ScopeFilter.
Note that I am using sbt 1.x here, but it should work with sbt 0.13 some minor change.
lazy val packageAll = taskKey[Unit]("package all the projects")
lazy val myTask = inputKey[Unit]("foo")
lazy val root = (project in file("."))
.aggregate(sub1, sub2)
.settings(
scalaVersion in ThisBuild := "2.12.4",
packageAll := {
(packageBin in Compile).all(nonRootsFilter).value
()
},
myTask := {
packageAll.value
}
)
lazy val sub1 = (project in file("sub1"))
lazy val sub2 = (project in file("sub2"))
def nonRootsFilter = {
import sbt.internal.inc.ReflectUtilities
def nonRoots: List[ProjectReference] =
allProjects filter {
case LocalProject(p) => p != "root"
case _ => false
}
def allProjects: List[ProjectReference] =
ReflectUtilities.allVals[Project](this).values.toList map { p =>
p: ProjectReference
}
ScopeFilter(inProjects(nonRoots: _*), inAnyConfiguration)
}
In the above, myTask depends on packageAll, which aggregates (packageBin in Compile) for all non-root subprojects.
sbt:root> myTask
[info] Packaging /Users/xxx/packageall/sub1/target/scala-2.12/sub1_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Packaging /Users/xxx/packageall/sub2/target/scala-2.12/sub2_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 0 s, completed Feb 2, 2018 7:23:23 PM
I may be wrong, but you are defining the verify task dependency only for the current project.
Maybe you can try:
Seq(
verifyTask in Global := {},
verifyTask <<= (verifyTask in Global).dependsOn(scctTestTask, scalastyleTask)
)
Or you can add the verifyTask settings to all your modules.