I struggled, for several days I have to admit, to configure integration test to a Scala Play project.
With Maven it is usually a relatively trivial, well documented step. SBT also does have excellent article, but it does not work for Play project without tweaking. All I found on Web so far were not working, partial, usually poorly commented posts, often for outdated versions of SBT or Play.
I succeed so I am sharing. I share a full complete solution, with plentiful comments, tested and known to work with recent, summer 2014, versions of Scala, Play and SBT; that is 2.10.x for Scala, 2.2.x for Play Framework, 13.x for SBT.
Goal
Configure special group of tests, let’s call them integration tests, so they are run separately, on a special command only, not as a part of a normal build.
- Integration tests to be in additional, separate source directory.
For Play projects it is suggested “it” placed directly under project root, so let’s follow it. - Integration tests are not run in normal build, with ordinary tests.
They will not run as a part on Jenkins (CI platform) project build. - Integration tests are run only on a special Play command (equivalent to Maven Profiles facility)
Useful to have them as a separate Jenkins task. - No special test tagging, or file naming pattern is required
- Special complication - integration tests are dependent on unit test, some helper classes are be shared, so integration test settings has to be aware of ordinary test sources.
- Try to reuse library dependencies already defined for ordinary tests, so no extra dependencies configuration is required.
Commands
Play console:
it:compile
..to compile just integration tests
it:test
..run just integration tests
test
..run unit tests as usual
Useful: Re-run idea
so IntelliJ recognises “it” as an additional test source directory so it can
syntax coloring etc is available and integration tests can be run from IDE.
Build.scala
import sbt._
import sbt.Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "fooapp"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"joda-time" % "joda-time" % "2.1",
"org.scalatest" % "scalatest_2.10" % "2.0" % "test, it",
"org.mockito" % "mockito-core" % "1.9.5" % "test, it"
)
Dependencies were shortened.
Note the the test, it
qualifier! It is essential, just test
is not enough. And no qualifier would indeed cause mixing test with production dependencies.
Define additional source directory for integration tests. This tests are not run in normal build, with unit tests.
/** integration test settings */
def itSettings = {
sourceDirectories in IntegrationTest <+= baseDirectory( _ / "it")
sourceDirectory in IntegrationTest <<= baseDirectory( _ / "it")
scalaSource in IntegrationTest <<= baseDirectory( _ / "it")
}
Perhaps setting both sourceDirectories
and sourceDirectory
is not essential and only one would do. Explicitly setting scalaSource
however is essential.
To define paths now using expression baseDirectory / "it"
- is deprecated in SBT 13.x, the baseDirectory( _ / "it")
or baseDirectory { _ / "it" }
is recommended.
lazy val IntegrationTestAltConf = config("it") extend(Test)
Based on original Play IntegrationTest. The difference is it is dow derived from Test (unit test) configuration and not Runtime configuration. The original definition is lazy val IntegrationTest = config("it") extend(Runtime)
in sbt.Configurations
but this way it was not it:compile
does not recognize test classes, like TestHelpers
used in my test. It is essential for projects where integration tests are not independent but depends on some shared test classes with other tests.
lazy val main = play.Project(appName, appVersion, appDependencies)
.settings(javaOptions in Test ++= Seq(
"-XX:MaxPermSize=512M",
"-Xms256M",
"-Xmx512M",
"-Xss1M"
))
.settings(testOptions in Test += Tests.Argument("-oF"))
..and many other usual Scala project setting. Shortened. Here goes integration test setup:
.configs(IntegrationTestAltConf)
It is a must, otherwise it will not recognize main sources and main libs. If the integration test were fully independent, shared nothing with unit tests, then standard IntegrationTest
could be used.
.settings(Defaults.itSettings : _*)
This makes command like it:compile
and it:run
possible from Play console
.settings(itSettings)
Set additional separate directory for integration tests, see itSettings()
method above.
}
That should be it. Don’t forget to run
reload
in Play console to check the new Build.scala validity
Useful: Re-run idea
so IntelliJ recognises “it” as an additional test source directory so it can
syntax coloring etc is available and integration tests can be run from IDE.
Links
http://www.scala-sbt.org/0.13.3/docs/Detailed-Topics/Testing#integration-tests
Integration tests for SBT - official documentation. Does not work from Play projects out of the box as they differ in build configuretions.https://groups.google.com/forum/#!topic/simple-build-tool/d7NwpTorTOA
Lots of goodies, but for older SBT versions. Suggested settings expression.settings(inConfig(IntegrationTest)(Defaults.testTasks): _*)
did not work for me, SBT 13.x.https://groups.google.com/forum/#!topic/play-framework/BZUEXuIGenw
Does Play support the standard SBT practice of keeping integration tests in a separate “it” folder?
Very close, but it did not compile for me (just missing other test sources?)http://stackoverflow.com/questions/10302458/excluding-a-scalatest-test-when-calling-my-tests-from-within-sbt
An alternative solution using Scala Test (org.scalatest.FlatSpec) tagging facility (org.scalatest.Tag). This would require explicitly mark relevant tests and then exclude them from build.
Similar: http://code.hootsuite.com/tagged-tests-with-sbt/
Similar: http://stackoverflow.com/questions/13064226/play-framework-customize-which-tests-are-run
Link SBT sources to Play project
I found it very useful to have SBT sources attached to my Play project. Sources are attached to binary library dependencies by Play command:
idea with-sources=yes
But this does not include SBT libraries. In my struggle with integration test configuration I had to check sources very often as documentation and examples are still rare or outdated. I’m not sure with Play but underlaying SBT can be persuaded to download its sources and link them to your Build.scala. Type in Play console:
update-sbt-classifiers
gen-idea sbt-classifiers
Source: http://stackoverflow.com/questions/17127367/sbt-sources-in-idea
The article is written for Sbt, but works for Play project without tweaks
Downside is, any subsequent re-run of idea
or idea with-sources=yes
will break the link to sources.
Written with StackEdit.