In specs2, conditionally executing subtests on result returned from function that may throw exceptions

bdd, scala, specs2, testing

Solution

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:

- if there's an exception with the `maybeGiveMeAThing` then the whole specification will blow up

- if you choose to exclude the examples using the `thing`, you will still have it being built

Another 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
    }
  }
}

Problem

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: - If a `Thing` was returned successfully, proceed with a set of subtests that analyze the contents of thing - If `maybeGiveMeAThing` threw an exception (any exception), skip the subtests that analyze thing, but continue with the rest of the tests My 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.)

Original source