Core DSL for defining test suites and individual tests with full ZIO integration and composition support.
Creates individual test cases with assertions.
/**
* Creates a pure test with the specified label and assertion
* @param label - Descriptive name for the test
* @param assertion - Test assertion that produces a TestResult
* @returns A test specification that can be run
*/
def test(label: String)(assertion: => TestResult)(implicit loc: SourceLocation): ZSpec[Any, Nothing]
/**
* Creates an effectful test with the specified label and ZIO-based assertion
* @param label - Descriptive name for the test
* @param assertion - ZIO effect that produces a TestResult
* @returns A test specification with environment and error requirements
*/
def testM[R, E](label: String)(assertion: => ZIO[R, E, TestResult])(implicit loc: SourceLocation): ZSpec[R, E]Usage Examples:
import zio.test._
import zio.test.Assertion._
test("string length") {
assert("hello")(hasSize(equalTo(5)))
}
testM("async operation") {
for {
result <- someAsyncOperation
} yield assert(result)(isSuccess)
}Creates test suites that group related tests together.
/**
* Creates a test suite containing multiple specs
* @param label - Descriptive name for the suite
* @param specs - Variable number of test specifications
* @returns Combined test specification
*/
def suite[R, E, T](label: String)(specs: Spec[R, E, T]*): Spec[R, E, T]
/**
* Creates an effectful test suite with specs computed at runtime
* @param label - Descriptive name for the suite
* @param specs - ZIO effect that produces an iterable of specs
* @returns Test specification that executes specs when computed
*/
def suiteM[R, E, T](label: String)(specs: ZIO[R, E, Iterable[Spec[R, E, T]]]): Spec[R, E, T]Usage Examples:
suite("Calculator Tests")(
test("addition") {
assert(2 + 2)(equalTo(4))
},
test("subtraction") {
assert(5 - 3)(equalTo(2))
}
)
suiteM("Dynamic Tests") {
ZIO.succeed(List(
test("test 1")(assert(true)(isTrue)),
test("test 2")(assert(false)(isFalse))
))
}The core Spec type that represents test specifications.
/**
* Core specification type that can be a suite or individual test
* @tparam R - Environment requirements
* @tparam E - Error type
* @tparam T - Test result type
*/
case class Spec[-R, +E, +T](caseValue: SpecCase[R, E, T, Spec[R, E, T]]) {
/** Combines this spec with another spec */
def +[R1 <: R, E1 >: E, T1 >: T](that: Spec[R1, E1, T1]): Spec[R1, E1, T1]
/** Applies a test aspect to transform behavior */
def @@[R0 <: R1, R1 <: R, E0, E1, E2 >: E0 <: E1](
aspect: TestAspect[R0, R1, E0, E1]
)(implicit ev1: E <:< TestFailure[E2], ev2: T <:< TestSuccess): ZSpec[R1, E2]
/** Adds annotation to the spec */
def annotate[V](key: TestAnnotation[V], value: V): Spec[R, Annotated[E], Annotated[T]]
/** Filters specs based on tags */
def filterTags(predicate: Set[String] => Boolean): Spec[R, E, T]
/** Provides environment layer to the spec */
def provideCustomLayer[E1 >: E, R0](layer: ZLayer[R0, E1, R]): Spec[R0, E1, T]
/** Transforms the spec structure */
def transform[R1, E1, T1](
f: SpecCase[R, E, T, Spec[R, E, T]] => SpecCase[R1, E1, T1, Spec[R1, E1, T1]]
): Spec[R1, E1, T1]
}Factory methods for creating different types of specifications.
object Spec {
/** Creates a labeled spec */
def labeled[R, E, T](label: String, spec: Spec[R, E, T]): Spec[R, E, T]
/** Combines multiple specs into one */
def multiple[R, E, T](specs: Chunk[Spec[R, E, T]]): Spec[R, E, T]
/** Creates a spec from a test case */
def test[R, E, T](test: T, annotations: TestAnnotationMap): Spec[R, E, T]
/** Creates a spec that uses managed resources */
def managed[R, E, T](spec: Managed[E, Spec[R, E, T]]): Spec[R, E, T]
}/**
* A test that requires environment R and may fail with error E
*/
type ZTest[-R, +E] = ZIO[R, TestFailure[E], TestSuccess]
/**
* A test specification for ZIO programs
*/
type ZSpec[-R, +E] = Spec[R, TestFailure[E], TestSuccess]
/**
* An annotated value containing test metadata
*/
type Annotated[+A] = (A, TestAnnotationMap)import zio.test._
import zio.test.Assertion._
import zio.test.environment.TestEnvironment
object CompleteSpecExample extends DefaultRunnableSpec {
def spec = suite("Complete Example")(
suite("Basic Tests")(
test("simple assertion") {
assert(2 + 2)(equalTo(4))
},
testM("effectful test") {
for {
value <- ZIO.succeed(42)
} yield assert(value)(isGreaterThan(40))
}
),
suite("Advanced Tests")(
test("multiple assertions") {
assertTrue(
"hello".length == 5,
List(1, 2, 3).size == 3,
Some(42).isDefined
)
}
) @@ TestAspect.parallel,
test("ignored test") {
assert(false)(isTrue)
} @@ TestAspect.ignore
)
}