This document covers the platform-specific test runners that execute ZIO tests within the SBT ecosystem.
The shared base class for all ZIO test tasks across platforms.
abstract class BaseTestTask[T](
taskDef0: sbt.testing.TaskDef,
testClassLoader: ClassLoader,
sendSummary: SendSummary,
args: zio.test.TestArgs,
spec: zio.test.ZIOSpecAbstract,
runtime: zio.Runtime[T],
console: zio.Console
) extends sbt.testing.Task {
final def taskDef(): sbt.testing.TaskDef
def execute(eventHandler: sbt.testing.EventHandler, loggers: Array[sbt.testing.Logger]): Array[sbt.testing.Task]
def tags(): Array[String]
// Protected methods for subclass customization
protected def sharedFilledTestLayer(implicit trace: zio.Trace): zio.ZLayer[Any, Nothing, zio.test.TestEnvironment with zio.ZIOAppArgs with zio.Scope]
}taskDef0: SBT task definition containing test class informationtestClassLoader: ClassLoader for loading test classessendSummary: Function for sending test summariesargs: ZIO test arguments and configurationspec: The ZIO test specification to executeruntime: ZIO runtime for test executionconsole: Console implementation for test outputReturns the SBT task definition.
baseTask.taskDef()
// Returns: sbt.testing.TaskDefExecutes the test task and returns any subtasks.
Parameters:
eventHandler: SBT event handler for test result reportingloggers: Array of SBT loggers for outputReturns: Array of additional tasks (typically empty)
Returns task tags for SBT categorization.
baseTask.tags()
// Returns: Array[String] (empty array)The full-featured JVM test runner with advanced capabilities.
final class ZTestRunnerJVM(
val args: Array[String],
val remoteArgs: Array[String],
testClassLoader: ClassLoader
) extends sbt.testing.Runner {
var renderer: zio.test.render.TestRenderer
var shutdownHook: Option[() => Unit]
val summaries: java.util.concurrent.atomic.AtomicReference[Vector[zio.test.Summary]]
def sendSummary(implicit trace: zio.Trace): SendSummary
def done(): String
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
def tasksZ(defs: Array[sbt.testing.TaskDef], console: zio.Console)(implicit trace: zio.Trace): Array[ZTestTask[zio.test.TestOutput]]
}renderer: Configurable test output renderer (default: ConsoleRenderer)shutdownHook: Optional cleanup function executed when tests completesummaries: Thread-safe collection of test summaries from all executed tasksCreates a summary sender that collects results for final reporting.
implicit val trace: zio.Trace = zio.Trace.empty
val sender = runner.sendSummary
// Returns: SendSummaryCompletes test execution and returns formatted summary.
val result = runner.done()
// Returns: String with formatted test resultsBehavior:
Creates SBT tasks from task definitions.
val tasks = runner.tasks(taskDefs)
// Returns: Array[sbt.testing.Task]ZIO-native version of task creation with enhanced configuration.
Parameters:
defs: Array of SBT task definitionsconsole: ZIO Console implementationReturns: Array of ZTestTask[TestOutput] with shared runtime and layers
Enhanced task implementation with signal handling.
final class ZTestTask[T](
taskDef: sbt.testing.TaskDef,
testClassLoader: ClassLoader,
sendSummary: SendSummary,
testArgs: zio.test.TestArgs,
spec: zio.test.ZIOSpecAbstract,
runtime: zio.Runtime[T],
console: zio.Console
) extends BaseTestTask(taskDef, testClassLoader, sendSummary, testArgs, spec, runtime, console)The JVM implementation includes signal handlers for debugging:
// Install handlers for fiber dumping
// Windows: SIGINT (Ctrl+C)
// Unix: SIGINFO, SIGUSR1
private def installSignalHandlers(): UnitJavaScript platform runners support distributed testing patterns.
final class ZMasterTestRunnerJS(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
) extends ZTestRunnerJS(args, remoteArgs, testClassLoader, "master")Used for single-process test execution.
final class ZSlaveTestRunnerJS(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader,
sendSummary: SendSummary
) extends ZTestRunnerJS(args, remoteArgs, testClassLoader, "slave")Used in distributed testing scenarios with custom summary handling.
sealed abstract class ZTestRunnerJS(
val args: Array[String],
val remoteArgs: Array[String],
testClassLoader: ClassLoader,
runnerType: String
) extends sbt.testing.Runner {
def sendSummary: SendSummary
val summaries: scala.collection.mutable.Buffer[zio.test.Summary]
def done(): String
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
def receiveMessage(summary: String): Option[String]
def serializeTask(task: sbt.testing.Task, serializer: sbt.testing.TaskDef => String): String
def deserializeTask(task: String, deserializer: String => sbt.testing.TaskDef): sbt.testing.Task
}Native platform runners with optimized concurrency primitives.
final class ZMasterTestRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
) extends ZTestRunnerNative(args, remoteArgs, testClassLoader, "master")final class ZSlaveTestRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader,
sendSummary: SendSummary
) extends ZTestRunnerNative(args, remoteArgs, testClassLoader, "slave")sealed abstract class ZTestRunnerNative(
val args: Array[String],
remoteArgs0: Array[String],
testClassLoader: ClassLoader,
runnerType: String
) extends sbt.testing.Runner {
def remoteArgs(): Array[String]
def sendSummary: SendSummary
val summaries: java.util.concurrent.ConcurrentLinkedQueue[zio.test.Summary]
def done(): String
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
def receiveMessage(summary: String): Option[String]
def serializeTask(task: sbt.testing.Task, serializer: sbt.testing.TaskDef => String): String
def deserializeTask(task: String, deserializer: String => sbt.testing.TaskDef): sbt.testing.Task
}import zio.test.sbt._
// JVM runner with custom configuration
val jvmRunner = new ZTestRunnerJVM(
args = Array("--testSearchTerms", "MyTest"),
remoteArgs = Array(),
testClassLoader = getClass.getClassLoader
)
// Configure custom renderer
jvmRunner.renderer = zio.test.render.LogAnnotationRenderer()
// Add shutdown hook
jvmRunner.shutdownHook = Some(() => println("Tests completed"))// Create tasks from test definitions
val tasks = runner.tasks(taskDefs)
// Execute tasks with event handling
val eventHandler: sbt.testing.EventHandler = ???
val loggers: Array[sbt.testing.Logger] = Array()
tasks.foreach { task =>
val subtasks = task.execute(eventHandler, loggers)
// Process any returned subtasks
}
// Get final results
val summary = runner.done()
println(summary)// Platform-specific runner creation
val runner = scala.util.Properties.isJavaAtLeastVersion("1.8") match {
case true => new ZTestRunnerJVM(args, remoteArgs, classLoader)
case false => ??? // Handle other platforms
}