In specs2, what is the proper way to express a pattern of subtests that only execute if its "parent" test returned a result without throwing an exception?
I have a function maybeGiveMeAThing
, and it can either return a Thing
, or throw exceptions.
A call looks like this:
val thing: Thing = maybeGiveMeAThing("foo", "bar" "baz"
)
I want to test that with a certain set of inputs, that maybeGiveMeAThing
successfully returns a Thing without throwing an exception, and using the Thing returned, do further tests to ensure that it is the correct Thing
returned for the parameters given to maybeGiveMeAThing
.
The way I have the tests currently set up, if the call to maybeGiveMeAThing
throws an exception, the entire test suite gets aborted. This would be the logic I prefer:
Thing
was returned successfully, proceed with a set of subtests that analyze the contents of thing maybeGiveMeAThing
threw an exception (any exception), skip the subtests that analyze thing, but continue with the rest of the testsMy existing test code looks roughly like:
// ...
"with good parameters" in {
var thing: Thing = null
"return a Thing without throwing an exception" in {
thing = maybeGiveMeAThing("some", "good", "parameters", "etc.")
} should not(throwA[Exception])
"the Thing returned should contain a proper Foo" in {
thing.foo mustBe "bar"
}
//... etc ...
}
// ...
}
...although this feels like it's way off from the right way to do it. What would be the proper way?
(I would like to avoid using var
s if I can help it.)
One possibility is to use a condition as in @alexwriteshere answer:
"parent test" in {
val thing: Option[Thing] = maybeGiveMeAThing("foo", "bar" "baz")
thing match {
case Some(thing) =>
"child test 1" in ok
"child test 2" in ok
case None =>
"skipped tests" in skipped
}
}
However you need to add an Example
in the None
case so that the block of the in
method has an acceptable type.
The big drawback with this approach though is that the specification is being executed while being defined. This means that:
maybeGiveMeAThing
then the whole specification will blow upthing
, you will still have it being builtAnother option is to use a Step
saying that any previous failure will skip all the next examples:
class MySpec extends mutable.Specification {
"This is a test with a thing" >> {
lazy val thing: Option[Thing] = maybeGiveMeAThing("foo", "bar" "baz")
"the thing should be ok" >> {
thing must beOk
}
step(stopOnFail = true)
"other examples with thing" >> {
"ex1" >> ok
"ex2" >> ok
}
}
}