When you want to specify an API, most of your examples are self-describing:
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
"when the collection has 1 element" >> { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
"when the collection has 2 elements" >> { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
"when the collection is empty" >> { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
It is a bit redundant to provide a textual description for these 3
examples because the code is pretty clear and simple. In this situation
you can use the eg operator to create an example where the
description will be the code itself:
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
eg { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
eg { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
eg { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
This prints:
[info] updateLast modifies the last element of a Seq
[info] Seq(1).updateLast(_ + 1) must ===(Seq(2))
[info] Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3))
[info] Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]())
Acceptance specifications are using interpolated strings so you can directly write:
class SeqSpecification extends Specification:
def is = s2"""
updateLast modifies the last element of a Seq
${Seq(1).updateLast(_ + 1) must ===(Seq(2))}
${Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3))}
${Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]())}
"""
There is a huge gotcha though! Each of these expressions needs an
implicit conversion to be included in the interpolated spec. And in
Scala, if you have a block of code returning a value of type
T, only the last expression of the block is
converted. This means that if there is a statement in the
block that throws an exception, this exception won’t be caught and the
whole specification will fail to be instantiated! So if you want to use
blocks as auto-examples you should better wrap them with an
eg call:
class SeqSpecification extends Specification:
def is = s2"""
This is a problematic specification
${ sys.error("ouch, this one is going to blow up the spec"); Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
${eg { sys.error("it's ok, this one is well protected"); Seq(1).updateLast(_ + 1) must ===(Seq(2)) }}
"""