scalatestingsbtscala.jsutest

Sbt hook for custom µtest test runner


I'm using µtest in a Scala sbt project. I want to run various test classes with a custom made test runner, which consists of code like this

val results = AnotherClassWithTests.myTests.run()
println(results.leaves.count(_.value.isSuccess))

I want it to be executed when running sbt test, and the only way I've found is to extend utest.Testsuite and leave the tests method empty.

This way, sbt will find the class and run it, but the solution doesn't seem ideal. I can prevent sbt's runner to execute AnotherClassWithTests by not having it extend utest.Testsuite, but still I'd get unneccessary output from the µtests default test runner along with my own ouput.

How can I hook my runner to sbt test without that hack and run all my tests with it, skipping µtests default runner?

Can I access the list of µ-tests that are detected by sbt, too?


Solution

  • You can completely override the behavior of the test task, with one that simply executes your main class. Taking inspiration from https://github.com/scala-js/scala-js/blob/v0.6.5/sbt-plugin/src/main/scala/scala/scalajs/sbtplugin/ScalaJSPluginInternal.scala#L547-L549

    /** Run a class in a given environment using a given launcher */
    def jsRun(env: JSEnv, cp: CompleteClasspath, mainCl: String,
        launcher: VirtualJSFile, jsConsole: JSConsole, log: Logger) = {
    
      log.info("Running " + mainCl)
      log.debug(s"with JSEnv of type ${env.getClass()}")
      log.debug(s"with classpath of type ${cp.getClass}")
    
      // Actually run code
      env.jsRunner(cp, launcher, log, jsConsole).run()
    }
    
    def launcherContent(mainCl: String) = {
      val parts = mainCl.split('.').map(s => s"""["${escapeJS(s)}"]""").mkString
      s"${CoreJSLibs.jsGlobalExpr}$parts().main();\n"
    }
    
    def memLauncher(mainCl: String) = {
      new MemVirtualJSFile("Generated launcher file")
        .withContent(launcherContent(mainCl))
    }
    
    test in Test := {
      val mainClass = "path.to.AnotherClassWithTests"
      jsRun((jsEnv in Test).value, (scalaJSExecClasspath in Test).value, mainClass,
          memLauncher(mainClass), (scalaJSConsole in Test).value, streams.value.log)
    }
    

    To obtain the list of tests that have been detected, you can use the sbt task (definedTests in Test).value, or possibly (definedTestNames in Test).value.