Core DSL for creating tests and test suites with support for nested suites, test organization, and ZIO effect integration.
Creates a single test case with a descriptive label and assertion.
/**
* Creates a test with the specified label and assertion
* @param label descriptive name for the test
* @param assertion test logic returning TestResult or ZIO effect
* @return test specification
*/
def test[R](label: String)(assertion: => ZIO[R, Any, TestResult]): Spec[R, Any]Usage Examples:
import zio.test._
// Simple test with assertTrue
test("addition works correctly") {
assertTrue(2 + 2 == 4)
}
// Effectful test
test("database connection") {
for {
connection <- Database.connect
isValid <- connection.isValid
} yield assertTrue(isValid)
}
// Test with custom assertion
test("list contains element") {
val list = List(1, 2, 3, 4, 5)
assert(list)(contains(3))
}Creates a test suite containing multiple tests or nested suites.
/**
* Creates a test suite with the specified label and child specifications
* @param label descriptive name for the suite
* @param specs child test specifications (tests or nested suites)
* @return suite specification
*/
def suite[R](label: String)(specs: Spec[R, Any]*): Spec[R, Any]Usage Examples:
import zio.test._
// Simple suite with multiple tests
suite("Math Operations")(
test("addition") { assertTrue(2 + 2 == 4) },
test("multiplication") { assertTrue(3 * 4 == 12) },
test("division") { assertTrue(10 / 2 == 5) }
)
// Nested suites
suite("API Tests")(
suite("User Endpoints")(
test("create user") { /* test logic */ },
test("get user") { /* test logic */ },
test("update user") { /* test logic */ }
),
suite("Product Endpoints")(
test("list products") { /* test logic */ },
test("create product") { /* test logic */ }
)
)Low-level effectful test type for advanced test construction.
/**
* Effectful test that may fail with TestFailure[E] or succeed with TestSuccess
*/
type ZTest[-R, +E] = ZIO[R, TestFailure[E], TestSuccess]
object ZTest {
/**
* Builds a test with an effectual assertion
* @param label test label
* @param assertion effectual test assertion
* @return ZTest instance
*/
def apply[R, E](label: String, assertion: => ZIO[R, E, TestResult]): ZIO[R, TestFailure[E], TestSuccess]
}Core specification type supporting composition and test aspect application.
/**
* A test specification that can be executed to produce test results
* @tparam R environment required to run the specification
* @tparam E error type that tests may fail with
*/
trait Spec[+R, +E] {
/**
* Apply a test aspect to this specification
* @param aspect test aspect to apply
* @return modified specification
*/
def @@[R1 <: R](aspect: TestAspect[Nothing, R1, Nothing, Any]): Spec[R1, E]
/**
* Transform the environment of this specification
* @param f transformation function
* @return specification with transformed environment
*/
def provideLayer[R0, R1, E1 >: E](layer: ZLayer[R0, E1, R1]): Spec[R0, E1]
}Usage Examples:
import zio.test._
import zio.test.TestAspect._
// Apply timeout aspect to entire suite
suite("Database Tests")(
test("slow query") { /* test logic */ },
test("batch insert") { /* test logic */ }
) @@ timeout(30.seconds)
// Apply multiple aspects
suite("Integration Tests")(
test("external API call") { /* test logic */ }
) @@ timeout(10.seconds) @@ eventually @@ flakyIndividual test case within a specification.
/**
* A single test case with metadata
* @param label descriptive test name
* @param test the test logic as ZIO effect
* @param annotations metadata attached to the test
*/
case class SpecCase[+R, +E](
label: String,
test: ZIO[R, TestFailure[E], TestSuccess],
annotations: TestAnnotationMap
)Base classes for creating test suites with standard patterns.
/**
* Abstract base class for ZIO test specifications
* @tparam R environment type required by tests
*/
abstract class ZIOSpec[R] {
/**
* The test specification to execute
*/
def spec: Spec[R, Any]
}
/**
* Base class for test specs with standard test environment
*/
abstract class ZIOSpecDefault extends ZIOSpec[TestEnvironment] {
/**
* Test specification using default test environment
*/
def spec: Spec[TestEnvironment, Any]
}Usage Examples:
import zio.test._
// Using ZIOSpecDefault (recommended)
object MyTestSpec extends ZIOSpecDefault {
def spec = suite("My Tests")(
test("basic test") {
assertTrue(1 + 1 == 2)
}
)
}
// Using ZIOSpec with custom environment
object CustomEnvSpec extends ZIOSpec[MyCustomEnv] {
def spec = suite("Custom Environment Tests")(
test("uses custom service") {
for {
result <- ZIO.serviceWithZIO[MyCustomService](_.doSomething())
} yield assertTrue(result.isSuccess)
}
)
}Type class for constructing suites from various input types.
/**
* Type class for constructing test suites from different input types
*/
trait SuiteConstructor[In] {
type OutEnvironment
type OutError
def apply(in: In): Spec[OutEnvironment, OutError]
}
// Instances for common types
implicit def functionSuiteConstructor[A, In](implicit
constructor: TestConstructor[In]
): SuiteConstructor[A => In]
implicit def specSuiteConstructor[R, E]: SuiteConstructor[Spec[R, E]]/**
* Interface for running test specifications
*/
trait TestRunner[R, E] {
def run(spec: Spec[R, E]): ZIO[R, Nothing, ExecutionEvent]
}
object TestRunner {
def default[R, E]: TestRunner[R, E]
}/**
* Events emitted during test execution
*/
sealed trait ExecutionEvent
case class Test(labels: List[String], test: Either[TestFailure[Any], TestSuccess]) extends ExecutionEvent
case class SuiteStarted(labels: List[String]) extends ExecutionEvent
case class SuiteCompleted(labels: List[String]) extends ExecutionEvent
case class TestStarted(labels: List[String]) extends ExecutionEvent
case class TestCompleted[E](labels: List[String], result: Either[TestFailure[E], TestSuccess]) extends ExecutionEvent