Search code examples
scalasbttypesafe-activator

SBT : Override behavior of task "test" to run only tests from default testSource folder, there are multiple test source folders


We have standard SBT project with standard directory structure.

The test folder contains all the JUnit tests.

We introduced a new folder othertests and the folder othertests is peer to folder test

The othertest folder contains some special test cases. The test classes names in the folder othertest can be easily distinguished from the normal JUnit tests.

Below is my working build.sbt configuration.

I have added the folder othertest in test sources using javaSources in Test SBT task.

We are using activator to run tests and do other stuff.

When I run activator> test I want all tests from the folder test only to run and I want to run tests from the folder othertests separately.

Questions.

  1. How to override the behavior of test tasks to filter out tests from the folder othertests
  2. Should I create shared modules to run normal junit tests separately and other junit tests separately.

Below is my build.sbt configuration

import java.io.PrintStream

import play.sbt.PlayJava
import play.twirl.sbt.Import._

name := "Service"

version := "5.1.0"

scalaVersion := "2.11.8"

routesGenerator := InjectedRoutesGenerator

lazy val ContractTest = config("contract") extend(Test)

def contractTestFilter(name: String): Boolean = name endsWith "ContractTest"

def ignoreContractTest(name: String): Boolean = !contractTestFilter(name)

lazy val root = (project in file("."))
  .enablePlugins(PlayJava)
  .configs(ContractTest)
    .settings(
      inConfig(ContractTest) (Defaults.testTasks),
      javaSource in Test := { (baseDirectory in Test) (_ / "contracttest") }.value,
      testOptions in ContractTest := Seq(Tests.Filter(contractTestFilter),Tests.Argument(TestFrameworks.JUnit, "-q", "-v", "-s")),
      testOptions in Test := Seq(Tests.Filter(ignoreContractTest),Tests.Argument(TestFrameworks.JUnit, "-q", "-v", "-s"))
    )

lazy val xyz = taskKey[Unit]("custom task to create loglayout jar file under lib folder")

xyz := {
  LogLayoutJar.build(scalaBinaryVersion.value, streams.value.log)
}

run := (run in Runtime).dependsOn(xyz).evaluated

javaOptions in Test ++= Seq("-Dconfig.resource=applic.tt.cnf")

libraryDependencies ++= Seq(
  json,
  javaWs,
  "org.mockito" % "mockito-all" % "1.10.19" % Test,
  "org.scalatestplus.play" %% "scalatestplus-play" % "1.5.1" % Test,
  "org.easytesting" % "fest-assert" % "1.4" % Test,
  "org.scalactic" %% "scalactic" % "2.2.0",
  "org.jmockit" % "jmockit" % "1.9" % Test,
  "com.portingle" % "slf4jtesting" % "1.0.0" % Test,
  "org.scalacheck" %% "scalacheck" % "1.12.6" % Test
)

resolvers ++= Seq(
  "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
)

parallelExecution in Test := runningTestInParallel

testGrouping in Test := groupByModule((externalDependencyClasspath in Test).value,
  (definedTests in Test).value, streams.value.log)

javacOptions ++= Seq(
  "-Xlint:unchecked",
  "-Xlint:deprecation"
)
scalacOptions ++= Seq(
  "-feature",
  "-language:implicitConversions",
  "-deprecation"
)

// Custom tasks //
val silenceSystemErr = taskKey[Unit]("Replaces System.err with a PrintStream to nowhere.")

silenceSystemErr := {
  System.setErr(new PrintStream(new DevNull))
  println("Messages System.err will not be printed.")
}

val restoreSystemErr = taskKey[Unit]("Restores the original System.err")

restoreSystemErr := {
  System.setErr(systemErr)
  println("Messages System.err will be printed.")
}

From jenkins we run tests using below command -

bin/activator -Dsbt.log.noformat=true -Denvironment_name=test -DsuppressLogging=true clean silenceSystemErr jacoco:cover

Thank You Rakesh


Solution

  • 1.

    You're contradicting yourself. Why add javaSources in Test if you don't want them to run when you run the Test command?

    What you should do is create an [Additional Test configuration|http://www.scala-sbt.org/0.13/docs/Testing.html#Additional+test+configurations] that extends Test and runs only tests inside your othertests folder.

    2.

    You can create another module. I personally don't like this idea because then I have to name the module according to what it tests and I have 2 separate modules that should actually only be one.

    A separate test module might be a good idea if you have some dependencies in your tests that slow down the overall build time of your module. For example imagine a Java project with Gatling performance tests. If the performance tests are in the same module then whenever I rebuild it it will also rebuild the gatling tests that require the scala compiler which is slower.

    Some people can live with this, I'm one of them. I prefer to have the tests in the same project and possibly suffer a time penalty when rebuilding the module. Which rarely happens I create different test configurations when needed.

    Another reason to choose separate modules for tests is when your tests depend on multiple modules and you don't want this module dependency at compile time for the src code.

    Some IDE's and/or languages might encourage the use of separate module for tests as I understand is the case for C# and Visual Studio (but I might be wrong here, don't take my word for it).