In specs2, subtests on the result returned by a function that may throw exceptions are conditionally executed

In specs2, what is the correct way to express a subtest pattern that only runs if its โ€œparentโ€ test returned a result without exception?

I have a maybeGiveMeAThing function, and it can either return Thing or exclude throws.

The call is as follows:

val thing: Thing = maybeGiveMeAThing("foo", "bar" "baz" )

I want to verify that with a specific set of inputs, maybeGiveMeAThing successfully returns Thing without throwing an exception, and using the returned Thing, run additional tests to make sure that this is the correct Thing returned for the parameters given to maybeGiveMeAThing .

As I have currently configured tests, if the maybeGiveMeAThing call throws an exception, the entire test suite is interrupted. This will be the logic that I prefer:

  • If a Thing was successfully returned, go to the set of subtests that analyze the contents of the thing
  • If maybeGiveMeAThing throws an exception (any exception), skip the subtests that analyze the subject, but continue with the rest of the tests.

My existing test code looks something like this:

 // ... "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 is similar to how to do it right. What will be the right way?
(I would like to avoid using var if I can help it.)

+4
source share
2 answers

One possibility is to use the condition, as in @alexwriteshere's 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 Example to the None case so that the in method block is of an acceptable type.

The big drawback with this approach is that the specification is implemented during the definition. It means that:

  • if there is an exception with maybeGiveMeAThing , then the whole specification will explode.
  • If you decide to exclude examples using thing , you will still build it

Another option is to use Step , saying that any previous failure will skip all of the following 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 } } } 
+4
source

Simple if / else with child cases will do what you want. Or you can force the maybeGiveMeAThing method to return a parameter and then map it.

 "parent test" in { val thing: Option[Thing] = maybeGiveMeAThing("foo", "bar" "baz") thing match { case Some(thing) => "child test 1" in { ... } "child test 2" in { ... } case None => // don't run additional tests } } 

If, perhaps, GiveMeAThing should throw an exception, you can catch it and force the method to return the parameter.

+3
source

All Articles