Intent’s philosophy is to include commonly used matchers for the Scala standard library
(including Future
, Option
and Either
) but not to go overboard. Instead Intent makes is
quite easy to defined your own matchers where needed.
In our experience, deeply nested or fluent matchers are often hard to discover and the tooling support (code completion) is limited by having to know each of the namespace identifiers until you get to the actual match.
Due to this, Intent strives to keep the matcher namespace as flat as possible altough some prefixes exists.
The convention used in the documentation is that the actual value is what is used as parameter to expect and the expected value value is what is used in the matcher paramter.
expect( <actual value> ).<matcher>( <expected value> )
The documentation for each matcher contains a reference to Intent’s own unit-tests for that specific matcher to serve as additional examples.
Types
The following types are currently supported:
- String
- Boolean
- Int
- Long
- Float
- Double
- Char
- Option
Prefixes
All matchers (unless clearly stated) supports the following matcher prefixes.
.not
Using the .not
prefix will cause the negated match to be expected.
expect(true).not.toEqual(false)
Matchers
.toEqual
Match the actual value to be equal to the expected value.
expect(true).not.toEqual(false)
To compare the values, the ==
operator is used behind the scenes.
The values can also be sequences (IterableOnce
/Array
), in which case they must
have the same length and elements on the same position must be equal.
.toHaveLength
Match a Seq
/List
(in fact, any IterableOnce
) to have the expected length.
expect(Seq("one")).toHaveLength(1)
.toContain
Match if a given sequence (either IterableOnce
or Array
) contains the expected element.
expect(Seq(1, 2, 3)).toContain(2)
It can also be used with a Map
to match if the given Map contains the expected key-value pair.
expect(Map("one" -> 1, "two" -> 2, "three" -> 3)).toContain("two" -> 2)
.toContainAllOf
Match if a given Map
contains all of the expected key-value pairs.
expect(Map("one" -> 1, "two" -> 2, "three" -> 3)).toContainAllOf("two" -> 2, "one" -> 1)
.toCompleteWith
Match the result of a Future
to equal the expected value.
expect(Future.successful("foo")).toCompleteWith("foo")
.toMatch
Match the result of a String using a regular expression.
expect(someString).toMatch("^a".r)
Note that the regular expression only needs to partially match the actual string, since we reckon that is the most common use case. Thus, the following test will pass:
expect("foo").toMatch("o+".r)
If a complete match is desired, use ^
as prefix and $
as suffix. For example,
this will fail:
expect("foo").toMatch("^o+$".r)
.toThrow
Test that a piece of code throws an exception, optionally with a particular message.
def div(n: Int, d: Int) =
require(d != 0, "Division by zero")
n / d
expect(div(5, 0)).toThrow[IllegalArgumentException]("requirement failed: Division by zero")
This matcher can be used in three different ways:
- With no expected message:
expect(div(5, 0)).toThrow[IllegalArgumentException]()
- With an exact expected message:
expect(div(5, 0)).toThrow[IllegalArgumentException]("requirement failed: Division by zero")
- With a regular expression, which is applied as a partial match:
expect(div(5, 0)).toThrow[IllegalArgumentException]("failed.*zero".r)
Note that since the argument to expect
is a block, testing of a more complex piece of
potentially-throwing code can be written as follows:
expect:
val numerator = 5
val denominator = 0
div(numerator, denominator)
.toThrow[IllegalArgumentException]()
toThrow
is satisified when the actual exception is of the same type as or a sub type of the
expected exception. Thus, the following test passes:
expect(div(5, 0)).toThrow[RuntimeException]()