Specs2 is a comprehensive testing framework and specification library for Scala that enables behavior-driven development (BDD) through executable specifications. It provides a rich domain-specific language for writing tests that read like natural language documentation, supports both mutable and immutable specification styles, and includes advanced matchers for various data types, custom matchers, and integration with property-based testing via ScalaCheck. The library offers multiple output formats including HTML, console, and JUnit XML reporting, making it suitable for both documentation generation and continuous integration environments.
libraryDependencies += "org.specs2" %% "specs2" % "3.3.1" % "test"import org.specs2._
import org.specs2.mutable._ // for mutable specifications
import org.specs2.matcher._ // for matchersFor Maven:
<dependency>
<groupId>org.specs2</groupId>
<artifactId>specs2_2.10</artifactId>
<version>3.3.1</version>
<scope>test</scope>
</dependency>import org.specs2._
// Immutable (functional) specification style
class CalculatorSpec extends Specification { def is = s2"""
Calculator should
add two numbers correctly $add
subtract two numbers correctly $subtract
handle edge cases $edge
"""
def add = {
val calc = new Calculator
calc.add(2, 3) must beEqualTo(5)
}
def subtract = {
val calc = new Calculator
calc.subtract(5, 2) must beEqualTo(3)
}
def edge = {
val calc = new Calculator
calc.divide(1, 0) must throwA[ArithmeticException]
}
}
// Mutable (imperative) specification style
import org.specs2.mutable._
class CalculatorMutableSpec extends Specification {
"Calculator" should {
"add two numbers correctly" in {
val calc = new Calculator
calc.add(2, 3) must beEqualTo(5)
}
"subtract two numbers correctly" in {
val calc = new Calculator
calc.subtract(5, 2) must beEqualTo(3)
}
}
}Specs2 is built around several key architectural patterns:
Fragment objects (text, examples, steps, actions)Base specification classes and traits for creating both immutable and mutable test specifications. Provides the foundation for all test writing in specs2.
abstract class Specification extends SpecificationLike
trait SpecificationLike extends ImmutableSpecificationStructure
with SpecificationCreation with SpecificationFeatures
abstract class Spec extends SpecLike
trait SpecLike extends ImmutableSpecificationStructure
with S2StringContext1 with AcceptanceDsl1 with MustMatchers1Mutable specification classes that use thrown expectations and imperative-style test definition. Ideal for developers who prefer traditional unit testing syntax.
// org.specs2.mutable package
abstract class Specification extends SpecificationLike
trait SpecificationLike extends SpecificationStructure
with SpecificationCreation with SpecificationFeatures
abstract class Spec extends SpecLikeComprehensive matcher system for assertions with type-safe composition, built-in matchers for common data types, and support for custom matchers.
trait Matcher[T] {
def apply[S <: T](expectable: Expectable[S]): MatchResult[S]
def and[S <: T](m: Matcher[S]): Matcher[S]
def or[S <: T](m: Matcher[S]): Matcher[S]
def not: Matcher[T]
}
trait Matchers extends AnyMatchers with StringMatchers
with TraversableMatchers with NumericMatchers
with ExceptionMatchers with OptionMatchers
with EitherMatchers with FutureMatchersDomain-specific language components for creating readable and expressive test specifications with natural language syntax.
trait AcceptanceDsl extends FragmentsDsl with SpecStructureDsl
with TitleDsl with ExampleDsl with ReferenceDsl
with TagDsl with ActionDsl
trait ExampleDsl {
def in[T: AsResult](t: => T): Fragment
def >>[T: AsResult](t: => T): Fragment
def should[T: AsResult](t: => T): Fragment
def can[T: AsResult](t: => T): Fragment
}Test runners, configuration options, and execution control for running specifications in various environments.
object Runner {
def execute(actions: Action[Unit], arguments: Arguments, exit: Boolean): Unit
}
case class Arguments(
plan: Boolean = false,
skipAll: Boolean = false,
stopOnFail: Boolean = false,
sequential: Boolean = false,
threadsNb: Int = Runtime.getRuntime.availableProcessors
)Flexible reporting system with console, HTML, and markdown output formats for generating documentation and test reports.
trait Reporter {
def report(spec: SpecificationStructure): Action[Unit]
}
trait TextPrinter extends Printer
trait MarkdownPrinter extends Printer
trait HtmlTemplateIntegration modules for JUnit, ScalaCheck property-based testing, and mock frameworks like Mockito.
// JUnit integration
@RunWith(classOf[JUnitRunner])
abstract class SpecificationWithJUnit extends Specification
// ScalaCheck integration
trait ScalaCheckProperty {
def prop[T: Arbitrary](f: T => Boolean): Prop
}
// Mockito integration
trait Mockito {
def mock[T: ClassTag]: T
}Specs2 provides string interpolation for embedding tests directly in specification text:
class MySpec extends Specification { def is = s2"""
This is a specification with embedded examples
example 1 $e1
example 2 $e2
"""
def e1 = 1 + 1 must beEqualTo(2)
def e2 = "hello" must have size(5)
}Matchers can be composed using logical operators:
// AND composition
result must (beGreaterThan(0) and beLessThan(100))
// OR composition
result must (beEqualTo("success") or beEqualTo("ok"))
// Negation
result must not(beEmpty)Create custom matchers for domain-specific assertions:
def beValidEmail = be matching("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b".r) ^^
((_:String).toLowerCase, "a valid email address")
"user@example.com" must beValidEmail// Core result types
sealed trait Result
case class Success(message: String = "") extends Result
case class Failure(message: String) extends Result
case class Error(message: String, exception: Throwable) extends Result
case class Skipped(message: String = "") extends Result
case class Pending(message: String = "") extends Result
// Fragment types
sealed trait Fragment
case class Text(text: String) extends Fragment
case class Example(description: String, body: Execution) extends Fragment
case class Step(action: () => Any) extends Fragment
case class Action(action: () => Any) extends Fragment
// Matcher result types
case class MatchResult[T](
expectable: Expectable[T],
message: Message,
negatedMessage: Message
)
case class Expectable[T](value: T, description: String)