It is very tempting to use foreach
to create examples or results from a sequence of values:
(1 to 3).foreach(i => "example " + i ! { i must ===(i) })
The problem with foreach
is that the return value of the expression above is Unit
. So you won’t be able to use it in an acceptance specification or a mutable one.
When we want to create a list of examples we need to return a Fragments
object. The long-winded way to do so is to use a foldLeft
:
(1 to 3).foldLeft(Fragments.empty)((res, i) => res.append("example " + i ! { i must ===(i) }))
Or, a bit fancier with foldMap
:
// Fragments has a Monoid instance so you can use the foldMap method
(1 to 3).toList.foldMap(i => Fragments("example " + i ! { i must ===(i) }))
Because this is a recurring pattern there are two methods encapsulating it:
// when the function only returns a Fragment
Fragment.foreach(1 to 3)(i => "example " + i ! { i must ===(i) }): Fragments
// when the function returns a Fragments object
Fragments.foreach(1 to 3) { i =>
"examples for " + i ^ br ^
"1 + " + i ! { (1 + i) must ===((i + 1)) } ^ br ^
"2 + " + i ! { (2 + i) must ===((i + 2)) }
}: Fragments
Now you can create a list of examples inside a “should” block in a mutable specification:
class MySpec extends mutable.Specification:
"this block should have lots of examples" >> {
Fragment.foreach(1 to 1000) { i =>
"example " + i ! { i must ===(i) }
}
}
Similarly, when you want to create a list of expectations inside an example, you should use a variant of foreach
and forall
methods:
foreach
and forall
methods of mutable.Specification
: class MySpec extends mutable.Specification:
"this collects results of all expectations and throws an exception" >> {
foreach(1 to 10) { i =>
i === 2
} // Collects results of all expectations. Throws an exception.
foreach(1 to 10) { i =>
i === i
} // This is not executed.
}
"this stops after the first failed expectation and throws an exception" >> {
forall(1 to 10) { i =>
i === 2
} // Stops after the first failed expectation. Throws an exception.
}
Result
, use Result.foreach
or Result.forall
:class MySpec extends mutable.Specification:
"this collects results of all expectations and returns a Result" >> {
Result.forall(1 to 10) { i =>
i === 2
}
}
"this stops after the first failed expectation and returns a Result" >> {
Result.foreach(1 to 10) { i =>
i === 2
}
}
Result.foreach
method uses the AsResult
typeclass