Reference card

Equality

The most common type of matcher is beEqualTo to test the equality of 2 values with the underlying == operator. Several syntaxes can be used, according to your own taste

Matcher Comment
1 must beEqualTo(1) the normal way
1 must be_==(1) with a symbol
1 must_== 1 my favorite!
1 mustEqual 1 if you dislike underscores
1 should_== 1 for should lovers
1 === 1 the ultimate shortcut
1 must be equalTo(1) with a literate style

There are also other notions of equality

Matcher Comment
beTypedEqualTo typed equality. a must beTypedEqualTo(b) will not work if a and b don’t have compatible types
be_=== synonym for beTypedEqualTo
a ==== b synonym for a must beTypedEqualTo(b)
a must_=== b similar to a must_== b but will not typecheck if a and b don’t have the same type
be_==~ check if (a: A) == conv(b: B) when there is an implicit conversion conv from B to A
beTheSameAs reference equality: check if a eq b (a must be(b) also works)
be a must be(b): synonym for beTheSameAs
beTrue, beFalse shortcuts for Boolean equality
beLike partial equality, using a PartialFunction[T, MatchResult[_]]: (1, 2) must beLike { case (1, _) => ok }

Note: the beEqualTo matcher is using the regular == Scala equality. However in the case of Arrays, Scala == is just using reference equality, eq. So the beEqualTo matcher has been adapted to use the .deep method on Arrays, transforming them to IndexedSeqs (possibly nested), before checking for equality, so that Array(1, 2, 3) === Array(1, 2, 3) (despite the fact that Array(1, 2, 3) != Array(1, 2, 3)).

Out of the box

These are the all the available matchers when you extend Specification

Specification matchers

Matching on strings is very common. Here are the matchers which can help you:

Matcher Description
beMatching or be matching check if a string matches a regular expression
=~(s) shortcut for beMatching("(.|\\s)*"+s+"(.|\\s)*")
find(exp).withGroups(a, b, c) check if some groups are found in a string
have length check the length of a string
have size check the size of a string (seen as an Iterable[Char])
be empty check if a string is empty
beEqualTo(b).ignoreCase check if 2 strings are equal regardless of casing
beEqualTo(b).ignoreSpace check if 2 strings are equal when you replaceAll("\\s", "")
beEqualTo(b).trimmed check if 2 strings are equal when trimmed
beEqualTo(b).ignoreSpace.ignoreCase you can compose them
contain(b) check if a string contains another one
startWith(b) check if a string starts with another one
endWith(b) check if a string ends with another one

Traversables can be checked with several matchers. If you want to check the size of a Traversable

  • check if it is empty
      Seq() must be empty
      Seq(1, 2, 3) must not be empty

  • check its size
      Seq(1, 2) must have size(2)
      Seq(1, 2) must have length(2) // equivalent to size
      Seq(1, 2) must have size(be_>=(1)) // with a matcher

note: you might have to annotate the haveSize matcher when using some combinators. For example: (futures: Future[Seq[Int]]) must haveSize[Seq[Int]](1).await

  • check its ordering (works with any type T which has an Ordering)
      Seq(1, 2, 3) must beSorted

Check each element individually

Then you can check the elements which are contained in the Traversable

  • if a simple value is contained
      Seq(1, 2, 3) must contain(2)

  • if a value matching a specific matcher is contained
      Seq(1, 2, 3) must contain(be_>=(2))

  • if a value passing a function returning a Result is contained (MatchResult, ScalaCheck Prop,...)
      Seq(1, 2, 3) must contain((i: Int) => i must be_>=(2))

  • note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in another you need to use a matcher
      Seq(Seq(1)) must contain(===(Seq(1)))

  • there are also 2 specialized matchers to check the string representation of the elements
      Seq(1234, 6237) must containMatch("23") // matches with ".*23.*"
      Seq(1234, 6234) must containPattern(".*234") // matches with !.*234"

For each of the check above you can indicate how many times the check should be satisfied:

  • Seq(1, 2, 3) must contain(be_>(0)).forall // this will stop after the first failure
  • Seq(1, 2, 3) must contain(be_>(0)).foreach // this will report all failures
  • Seq(1, 2, 3) must contain(be_>(0)).atLeastOnce
  • Seq(1, 2, 3) must contain(be_>(2)).atMostOnce
  • Seq(1, 2, 3) must contain(be_>(2)).exactly(1.times)
  • Seq(1, 2, 3) must contain(be_>(2)).exactly(1)
  • Seq(1, 2, 3) must contain(be_>(1)).between(1.times, 2.times)
  • Seq(1, 2, 3) must contain(be_>(1)).between(1, 2)

Check all elements

The other types of checks involve comparing the Traversable elements to other elements (values, matchers, function returning a Result)

  • with a set of values
      Seq(1, 2, 3, 4) must contain(2, 4)
      which is the same thing as
      Seq(1, 2, 3, 4) must contain(allOf(2, 4))

  • with a set of matchers
      Seq(1, 2, 3, 4) must contain(allOf(be_>(0), be_>(1)))

  • checking that the order is satisfied
      Seq(1, 2, 3, 4) must contain(allOf(be_>(0), be_>(1)).inOrder)

Note that allOf tries to make each check be successful at least once, even if it is on the same value. On the other hand, if you want to specify that each check must succeed on a different value you should use onDistinctValues. For example this will fail:
Seq(1) must contain(allOf(1, 1)).onDistinctValues

The eachOf method does the same thing (and this example will fail as well):
Seq(1) must contain(eachOf(1, 1))

Another frequent use of Traversable matchers is to check if the Traversable have the right number of elements. For this you can use:

  • atLeast, which is actually another name for allOf, where the traversable can contain more elements than required
      Seq(1, 2, 3, 4) must contain(atLeast(2, 4))

  • atMost where the traversable can not contain more elements than required
      Seq(2, 3) must contain(atMost(2, 3, 4))

  • exactly where the traversable must contain exactly the specified number of elements
      Seq(1, 2) must contain(exactly(2, 1))

The atLeast/atMost/exactly operators work on distinct values by default (because this is easier for counting the correspondence between actual values and expected ones). However you can use onDistinctValues(false) if you don't care.

Finally, if you want to get the differences between 2 traversables:

Seq(2, 4, 1) must containTheSameElementsAs(Seq(1, 4, 2))

Numerical values can be compared with the following matchers

  • beLessThanOrEqualTo compares any Ordered type with <=
        1 must be_<=(2)
        1 must beLessThanOrEqualTo(2)

  • beLessThan compares any Ordered type with <
        1 must be_<(2)
        1 must beLessThan(2)

  • beGreaterThanOrEqualTo compares any Ordered type with >=
        2 must be_>=(1)
        2 must beGreaterThanOrEqualTo(1)

  • beGreaterThan compares any Ordered type with >
        2 must be_>(1)
        2 must beGreaterThan(1)

  • beCloseTo check if 2 Numerics are close to each other
        1.0 must beCloseTo(1, 0.5)
        4 must be ~(5 +/- 2)
        4.994 must beCloseTo(5.0 within 2.significantFigures)

  • beBetween check if a value is between 2 others
        5 must beBetween(3, 6)
        5 must beBetween(3, 6).excludingEnd
        5 must beBetween(4, 6).excludingStart
        5 must beBetween(4, 6).excludingBounds
        // with brackets notation
        5 must (be[(4, 7)])
        5 must (be[(4, 6)[)
                                                                                                                   .

There are several matchers to check Option and Either instances:

  • beSome check if an element is Some(_)
  • beSome(exp) check if an element is Some(exp)
  • beSome(matcher) check if an element is Some(a) where a satisfies the matcher
  • beSome(function: A => AsResult[B]) check if an element is Some(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Some you need to use a matcher: beSome(===(Seq(1)))
  • beSome.which(function) check if an element is Some(_) and satisfies a function returning a boolean
  • beSome.like(partial function) check if an element is Some(_) and satisfies a partial function returning a MatchResult
  • beNone check if an element is None
  • beAsNoneAs check if 2 values are equal to None at the same time
  • beRight check if an element is Right(_)

  • beRight(exp) check if an element is `Right(exp)
  • beRight(matcher) check if an element is Right(a) where a satisfies the matcher
  • beRight(function: A => AsResult[B]) check if an element is Right(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Right you need to use a matcher: beRight(===(Seq(1)))
  • beRight.like(partial function) check if an element is Right(_) and satisfies a partial function returning a MatchResult
  • beLeft check if an element is Left(_)

  • beLeft(exp) check if an element is Left(exp)
  • beLeft(matcher) check if an element is Left(a) where a satisfies the matcher
  • beLeft(function: A => AsResult[B]) check if an element is Left(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Left you need to use a matcher: beLeft(===(Seq(1)))
  • beLeft.like(partial function) check if an element is Left(_) and satisfies a partial function returning a MatchResult

There are several matchers to check Try instances:

  • beSuccessfulTry check if an element is Success(_)
  • beSuccessfulTry.withValue(exp) check if an element is Success(_)
  • beSuccessfulTry.withValue(matcher) check if an element is Success(a) where a satisfies the matcher
  • beSuccessfulTry.withValue(function: A => AsResult[B]) check if an element is Success(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Success you need to use a matcher: beSuccessfulTry.withValue(===(Seq(1)))
  • beSuccessfulTry.which(function) check if an element is Success(_) and satisfies a function returning a boolean
  • beSuccessfulTry.like(partial function) check if an element is Success(_) and satisfies a partial function returning a MatchResult
  • beFailedTry check if an element is Failure(_)
  • beFailedTry.withThrowable[T] check if an element is Failure(t: T)
  • beFailedTry.withThrowable[T](pattern) check if an element is Failure(t: T) and t.getMessage matches pattern

Testing Futures is quite easy with specs2. You can transform any Matcher[T] into a Matcher[Future[T] with the await method

Future(1) must be_>(0).await

You can also specify a timeout value and a number of retries

Future { Thread.sleep(100); 1 } must be_>(0).await(retries = 2, timeout = 100.millis)

// only retries, timeout is 1.second
Future { Thread.sleep(100); 1 } must be_>(0).retryAwait(retries = 2)

// only timeout, retries = 0
Future { Thread.sleep(100); 1 } must be_>(0).awaitFor(100.millis)

Another possibility is for you to obtain a Future[MatchResult[T]] (or any Future[R] where R has an AsResult typeclass instance). In that case you can use await directly on the Future to get a Result

Future(1 === 1).await
Future(1 === 1).await(retries = 2, timeout = 100.millis)

Scalaz Futures

All of the above is applicable to scalaz.concurrent.Future by using the method attempt instead of await.

Execution

The await/attempt methods require an implicit org.specs2.concurrent.ExecutionEnv (see here for more details). You can pass one in the body of your examples:

import org.specs2.matcher.FuturezMatchers._

class MyFutureSpec extends Specification { def is = s2"""

 Let's check this scala future ${ implicit ee: EE =>
   Future(1) must be_>(0).await
 }

 Let's check this scalaz future ${ implicit ee: EE =>
   scalaz.concurrent.Future(1) must be_>(0).attempt
 }

"""
  type EE = ExecutionEnv
}

// in a mutable specification
class MyMutableFutureSpec extends mutable.Specification {

  "Let's check this scala future" >> { implicit ee: EE =>
    Future(1) must be_>(0).await
  }

  "Let's check this scalaz future" >> { implicit ee: EE =>
    scalaz.concurrent.Future(1) must be_>(0).attempt
  }

  type EE = ExecutionEnv
}

Time factor

Some actions can be a lot slower when executed on a continuous integration server rather than a developer machine and some timeouts will fail.
You can avoid this by setting the timeFactor argument which will multiply the durations used when awaiting / attempting by a constant factor.

sbt> testOnly *MyFuturesSpec* -- timeFactor 3

specs2 offers very compact ways of checking that some exceptions are thrown:

  • throwA[ExceptionType] check if a block of code throws an exception of the given type
  • throwA[ExceptionType](message = "boom") additionally check if the exception message is as expected (message is
    being interpreted as a regular expression)
  • throwA(exception) or throwAn(exception) check if a block of code throws an exception of the same type, with the
      same message
  • throwA[ExceptionType].like { case e => e must matchSomething } or
      throwA(exception).like { case e => e must matchSomething } check that the thrown exception satisfies a property
  • throwA[ExceptionType](me.like { case e => e must matchSomething } or
      throwA(exception).like { case e => e must matchSomething } check that the thrown exception satisfies a property

For all the above matchers you can use throwAn instead of throwA if the exception name starts with a vowel for better
readability.

Maps have their own matchers as well, to check keys and values:

  • haveKey check if a Map has a given key
        Map(1 -> "1") must haveKey(1)

  • haveKeys check if a Map has several keys
        Map(1 -> "1", 2 -> "2") must haveKeys(1, 2)

  • haveValue check if a Map has a given value
        Map(1 -> "1") must haveValue("1")

  • haveValues check if a Map has several values
        Map(1 -> "1", 2 -> "2") must haveValues("1", "2")

  • havePair check if a Map has a given pair of values
        Map(1 -> "1") must havePair(1 -> "1")

  • havePairs check if a Map has some pairs of values
        Map(1->"1", 2->"2", 3->"3") must havePairs(1->"1", 2->"2")

But Maps are also Partial Functions, so:

  • beDefinedAt check if a PartialFunction is defined for a given value
        partial must beDefinedAt(1)

  • beDefinedBy check if a PartialFunction is defined for a given value
      and returns another one
        partial must beDefinedBy(1 -> true)

These matchers can be used with any object, regardless of its type:

  • beLike { case exp => result } check if an object is like a given pattern. result can be any expression using a matcher
  • beLike { case exp => exp must beXXX } check if an object is like a given pattern, and verifies a condition
  • beNull check if an object is null
  • beAsNullAs when 2 objects must be null at the same time if one of them is null
  • beOneOf(a, b, c) check if an object is one of a given list
  • haveClass check the class of an object
  • haveSuperclass check if the class of an object as another class as one of its ancestors
  • haveInterface check if an object is implementing a given interface
  • beAssignableFrom check if a class is assignable from another
  • beAnInstanceOf[T] check if an object is an instance of type T

Optional

Those matchers are optional. To use them, you need to add a new trait to your specification:

Optional data matchers

There are several matchers to check scalaz.\/ instances:

  • be_\/- checks if an element is \/-(_)
  • be_\/-(exp) checks if an element is `\/-(exp)
  • be_\/-(matcher) checks if an element is \/-(a) where a satisfies the matcher
  • be_\/-(function: A => AsResult[B]) checks if an element is \/-(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in \/- you need to use a matcher: be_\/-(===(Seq(1)))
  • be_\/-.like(partial function) checks if an element is \/-(_) and satisfies a partial function returning a MatchResult
  • be_-\/ checks if an element is -\/(_)

  • be_-\/(exp) checks if an element is -\/(exp)
  • be_-\/(matcher) checks if an element is -\/(a) where a satisfies the matcher
  • be_-\/(function: A => AsResult[B]) checks if an element is -\/(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in -\/ you need to use a matcher: be_-\/(===(Seq(1)))
  • be_-\/.like(partial function) checks if an element is -\/(_) and satisfies a partial function returning a MatchResult

There are several matchers to check cats.Xor instances:

  • beXorRight checks if an element is Right(_)
  • beXorRight(exp) checks if an element is `Right(exp)
  • beXorRight(matcher) checks if an element is Right(a) where a satisfies the matcher
  • beXorRight(function: A => AsResult[B]) checks if an element is Right(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Right you need to use a matcher: beXorRight(===(Seq(1)))
  • beXorRight.like(partial function) checks if an element is Right(_) and satisfies a partial function returning a MatchResult
  • beXorLeft checks if an element is Left(_)

  • beXorLeft(exp) checks if an element is Left(exp)
  • beXorLeft(matcher) checks if an element is Left(a) where a satisfies the matcher
  • beXorLeft(function: A => AsResult[B]) checks if an element is Left(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Left you need to use a matcher: beXorLeft(===(Seq(1)))
  • beXorLeft.like(partial function) checks if an element is Left(_) and satisfies a partial function returning a MatchResult

There are several matchers to check scalaz.Validation instances:

  • beSuccess checks if an element is Success(_)
  • beSuccess(exp) checks if an element is `Success(exp)
  • beSuccess(matcher) checks if an element is Success(a) where a satisfies the matcher
  • beSuccess(function: A => AsResult[B]) checks if an element is Success(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Success you need to use a matcher: beSuccess(===(Seq(1)))
  • beSuccess.like(partial function) checks if an element is Success(_) and satisfies a partial function returning a MatchResult
  • beFailure checks if an element is Failure(_)

  • beFailure(exp) checks if an element is Failure(exp)
  • beFailure(matcher) checks if an element is Failure(a) where a satisfies the matcher
  • beFailure(function: A => AsResult[B]) checks if an element is Failure(a) where function(a) returns a successful Result
    (note that a Seq[A] is also a function Int => A so if you want to check that a sequence is contained in Failure you need to use a matcher: beFailure(===(Seq(1)))
  • beFailure.like(partial function) checks if an element is Failure(_) and satisfies a partial function returning a MatchResult

There are several matchers to check scalaz.concurrent.Task instances. To use them, you need to include the specs2-scalaz jar in your dependencies and mix in the TaskMatchers trait to your specification.

Then you can use:

  • returnOk to check if a Task completes successfully
  • returnBefore(duration) to check if a Task completes successfully before the specified duration
  • returnValue(matcher) to check if a Task successfully returns a value that satisfies the matcher
  • returnValue(function: A => AsResult[B]) to check if a Task completes successfully with a value a, where function(a) returns a successful Result. This can be used to do conditional assertions that depend on which value is returned by your Task
  • failWith[ExceptionType] to check if a Task fails with an Exception of the given type

Task execution

Please note that all the matchers above will run the Task for you, you should not call .run/.unsafePerformSync on them in your tests.

There is a special support for matching case classes:

  1. using shapeless to "project" a case class to another one containing less fields to match
  2. using a matcher macro

Both approaches are not incompatible, you can restrict the number of fields to match the remaining fields with more
  precise criteria.

Case class projection

You need to add the specs2-shapeless module to your project dependencies and add the org.specs2.shapeless.Projection._
import to your file.

Then you can "project" a type A on a "smaller" type B:

import org.specs2.shapeless.Projection._
    
case class User(id: Int, name: String, age: Int)
case class ExpectedUser(name: String, age: Int)


val u = User(123, "Martin", 58)

u.projectOn[ExpectedUser] must_== ExpectedUser("Martin", 58)

Matcher macro

You to add the specs2-matcher-extra module to your project dependencies and add the org.specs2.matcher.MatcherMacros trait to your specification.

Then, with the matchA matcher you can check the values of case class attributes:

// case class for a Cat
case class Cat(name: String = "", age: Int = 0, kitten: Seq[Cat] = Seq())
// a given cat
val cat = Cat(name = "Kitty", age = 6, kitten = Seq(Cat("Oreo", 1), Cat("Ella", 2)))

// this cat must be a Cat
cat must matchA[Cat]

// check the value of "name"
cat must matchA[Cat].name("Kitty")

// check the value of "age" using a matcher
def is[A](a: A) = be_==(a)
cat must matchA[Cat].age(is(6))

// check the value of "kitten" using a function returning a Result
cat must matchA[Cat].kitten((_:Seq[Cat]) must haveSize(2))

// matchers can be chained
cat must matchA[Cat]
  .name("Kitty")
  .age(is(6))
  .kitten((_:Seq[Cat]) must haveSize(2))

That's only if you want to check the result of other matchers!

// you need to extend the ResultMatchers trait
class MatchersSpec extends Specification with matcher.ResultMatchers { def is =
  "beMatching is using a regexp" ! {
    ("Hello" must beMatching("h.*")) must beSuccessful
  }
}

Sometimes you just want to specify that a block of code is going to terminate. The org.specs2.matcher.TerminationMatchers trait is here to help. If you mix in that trait, you can write:

Thread.sleep(100) must terminate

// the default is retries = 0, sleep = 100.millis
Thread.sleep(100) must terminate(retries = 1, sleep = 60.millis)

Note that the behaviour of this matcher is a bit different from the eventually operator. In this case, we let the current Thread sleep during the given sleep time and then we check if the computation is finished, then, we retry for the given number of retries.

In a further scenario, we might want to check that triggering another action is able to unblock the first one:

action1 must terminate.when(action2)
action1 must terminate.when("starting the second action", action2)
action1 must terminate(retries=3, sleep=100.millis).when(action2)

When a second action is specified like that, action1 will be started and action2 will be started on the first retry. Otherwise, if you want to specify that action1 can only terminate when action2 is started, you write:

action1 must terminate.onlyWhen(action2)

ExecutionEnv

The terminate matcher needs an implicit ExecutionEnv to be used. See the page to learn how to get one.