SBT test framework integration for ZIO Test, providing infrastructure to run ZIO-based tests within SBT build environments across JVM, JavaScript, and Native platforms
npx @tessl/cli install tessl/maven-dev-zio--zio-test-sbt_3@1.0.0SBT test framework integration for ZIO Test, providing the necessary infrastructure to run ZIO-based tests within SBT build environments across JVM, JavaScript, and Native platforms. This library implements the SBT testing interface protocols and provides test runners, event handlers, and summary reporting capabilities for ZIO Test specifications.
build.sbt: libraryDependencies += "dev.zio" %% "zio-test-sbt" % "1.0.18"import zio.test.sbt._For SBT framework integration:
import zio.test.sbt.ZTestFrameworkFor custom test tasks:
import zio.test.sbt.{BaseTestTask, SendSummary}The framework is automatically detected by SBT when included as a dependency. ZIO Test specs extending AbstractRunnableSpec are automatically discovered and executed:
import zio.test._
import zio.test.Assertion._
object MyTestSuite extends DefaultRunnableSpec {
def spec = suite("MyTestSuite")(
test("basic test") {
assert(1 + 1)(equalTo(2))
},
test("async test") {
for {
result <- ZIO.succeed(42)
} yield assert(result)(equalTo(42))
}
)
}The library follows SBT's testing framework protocol with ZIO-specific implementations:
The main entry point for SBT integration.
final class ZTestFramework extends sbt.testing.Framework {
override val name: String
val fingerprints: Array[sbt.testing.Fingerprint]
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): ZTestRunner
}final class ZTestFramework extends sbt.testing.Framework {
override def name(): String
override def fingerprints(): Array[sbt.testing.Fingerprint]
def runner(args: Array[String], remoteArgs: Array[String], testClassLoader: ClassLoader): sbt.testing.Runner
def slaveRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader,
send: String => Unit
): sbt.testing.Runner
}The framework provides:
RunnableSpecFingerprintPlatform-specific implementations for executing ZIO tests within SBT.
final class ZTestRunner(
val args: Array[String],
val remoteArgs: Array[String],
testClassLoader: ClassLoader
) extends sbt.testing.Runner {
val summaries: java.util.concurrent.atomic.AtomicReference[Vector[zio.test.Summary]]
val sendSummary: SendSummary
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
def done(): String
}abstract class ZTestRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader,
runnerType: String
) extends sbt.testing.Runner {
def sendSummary: SendSummary
def tasks(defs: Array[sbt.testing.TaskDef]): Array[sbt.testing.Task]
def done(): String
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
}
class ZMasterTestRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader
) extends ZTestRunner
class ZSlaveTestRunner(
args: Array[String],
remoteArgs: Array[String],
testClassLoader: ClassLoader,
sendSummary: SendSummary
) extends ZTestRunnerBase class for executing individual ZIO test specifications.
abstract class BaseTestTask(
taskDef0: sbt.testing.TaskDef,
testClassLoader: ClassLoader,
sendSummary: SendSummary,
args: zio.test.TestArgs
) extends sbt.testing.Task {
val testClassLoader: ClassLoader
val sendSummary: SendSummary
val args: zio.test.TestArgs
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]
}Platform-specific task implementations:
// JVM Task
class ZTestTask(
taskDef: sbt.testing.TaskDef,
testClassLoader: ClassLoader,
sendSummary: SendSummary,
testArgs: zio.test.TestArgs
) extends BaseTestTask
// JS/Native Task (with async execution)
class ZTestTask(
taskDef: sbt.testing.TaskDef,
testClassLoader: ClassLoader,
runnerType: String,
sendSummary: SendSummary,
testArgs: zio.test.TestArgs
) extends BaseTestTask {
def execute(
eventHandler: sbt.testing.EventHandler,
loggers: Array[sbt.testing.Logger],
continuation: Array[sbt.testing.Task] => Unit
): Unit
}SBT-compatible events generated from ZIO test execution results.
// JVM/JS Implementation
case class ZTestEvent(
fullyQualifiedName: String,
selector: sbt.testing.Selector,
status: sbt.testing.Status,
maybeThrowable: Option[Throwable],
duration: Long,
fingerprint: sbt.testing.Fingerprint
) extends sbt.testing.Event {
def throwable(): sbt.testing.OptionalThrowable
}
// Native Implementation (with explicit overrides)
case class ZTestEvent(
fullyQualifiedName0: String,
selector0: sbt.testing.Selector,
status0: sbt.testing.Status,
maybeThrowable: Option[Throwable],
duration0: Long,
fingerprint0: sbt.testing.Fingerprint
) extends sbt.testing.Event {
override def fullyQualifiedName(): String
override def selector(): sbt.testing.Selector
override def status(): sbt.testing.Status
override def duration(): Long
override def fingerprint(): sbt.testing.Fingerprint
def throwable(): sbt.testing.OptionalThrowable
}
object ZTestEvent {
def from[E](
executedSpec: zio.test.ExecutedSpec[E],
fullyQualifiedName: String,
fingerprint: sbt.testing.Fingerprint
): Seq[ZTestEvent]
}Customizable policies for merging and organizing test tasks.
abstract class ZTestTaskPolicy {
def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task]
}
class ZTestTaskPolicyDefaultImpl extends ZTestTaskPolicy {
override def merge(zioTasks: Array[ZTestTask]): Array[sbt.testing.Task] = zioTasks.toArray
}Type-safe summary handling with platform-specific serialization support.
type SendSummary = zio.URIO[zio.test.Summary, Unit]
object SendSummary {
def fromSend(send: zio.test.Summary => Unit): SendSummary
def fromSendM(send: zio.test.Summary => zio.UIO[Unit]): SendSummary
def noop: SendSummary
}For JavaScript/Native distributed testing:
object SummaryProtocol {
def serialize(summary: zio.test.Summary): String
def deserialize(s: String): Option[zio.test.Summary]
def escape(token: String): String
def unescape(token: String): String
}Fingerprint for automatic discovery of ZIO test specifications.
object RunnableSpecFingerprint extends sbt.testing.SubclassFingerprint {
def superclassName(): String
def isModule(): Boolean
def requireNoArgConstructor(): Boolean
}// Re-exported from zio.test
type Summary = zio.test.Summary
type TestArgs = zio.test.TestArgs
type ExecutedSpec[E] = zio.test.ExecutedSpec[E]
type AbstractRunnableSpec = zio.test.AbstractRunnableSpec
// SBT Testing API types (from sbt.testing._)
type Framework = sbt.testing.Framework
type Runner = sbt.testing.Runner
type Task = sbt.testing.Task
type TaskDef = sbt.testing.TaskDef
type Event = sbt.testing.Event
type EventHandler = sbt.testing.EventHandler
type Logger = sbt.testing.Logger
type Fingerprint = sbt.testing.Fingerprint
type SubclassFingerprint = sbt.testing.SubclassFingerprint
type Selector = sbt.testing.Selector
type TestSelector = sbt.testing.TestSelector
type Status = sbt.testing.Status
type OptionalThrowable = sbt.testing.OptionalThrowableZTestRunner implementationSummaryProtocolZTestEvent implementation with explicit method overridesTest failures are converted to appropriate SBT events:
TestFailure.Assertion becomes AssertionErrorTestFailure.Runtime becomes RuntimeExceptionAbstractRunnableSpectestOptions