Some specifications need to be fine-tuned and constantly modified. Sometimes to access a specific environment, or to disable some examples, or to execute more ScalaCheck properties. For all those situations it is desirable to modify the specification directly from the command-line without having to recompile it.
Let’s see first how to use the command line to modify the outcome of just one example:
class SpecificationWithArgs extends Specification { def is = s2"""
This example is controlled from the command line $e1
"""
def e1 = (commandLine: CommandLine) =>
if (commandLine.isSet("isOk")) 1 must_== 1
else 1 must_== 2
}
With a mutable specification the code is similar:
class SpecificationWithArgs extends mutable.Specification {
"This example is controlled from the command line" in { commandLine: CommandLine =>
if (commandLine.isSet("isOk")) 1 must_== 1
else 1 must_== 2
}
}
You can also drive the creation of the full specification with command line arguments:
class SpecificationWithArgs extends Specification with CommandLineArguments { def is(commandLine: CommandLine) =
if (commandLine.isSet("small"))
s2"""
This is a small specification
with one example $e1
"""
else
s2"""
This is a BIG specification
with many examples ${ Fragment.foreach(1 to 1000)(i => "ex"+i ! ok) }
"""
def e1 = ok
}
For a mutable specification we can use almost the same syntax but the CommandLineArguments
trait must come from the org.specs2.specification.mutable
package:
class SpecificationWithArgs extends mutable.Specification with specification.mutable.CommandLineArguments {
def is(commandLine: CommandLine) =
if (commandLine.isSet("small"))
"This is a small specification" should {
"with one example" in { 1 must_== 1 }
}
else
"This is a small specification" >> {
"with lots of examples" >> Fragment.foreach(1 to 1000)(i => "ex"+i >> ok)
}
}
The next thing you might want to control is contexts. Instead of using the BeforeEach
/ AfterEach
/ AroundEach
traits directly you will need to implement the ContextWithCommandLineArguments
trait and provide the appropriate context object:
class SpecificationWithArgs extends Specification with ContextWithCommandLineArguments { def is = s2"""
This is a specification with a context depending on command line arguments
with one example $ok
"""
/** you need to define this method */
def context = (commandLine: CommandLine) =>
new Before {
def before = if (commandLine.isSet("dobefore")) println("before!")
}
}
The final situation where you would need to use command-line arguments is with a ForEach
trait. If you want to influence the injection of data with the command line, the ForEachWithCommandLineArguments
trait needs to be mixed in:
class SpecificationWithArgs extends Specification with ForEachWithCommandLineArguments[Int] { def is = s2"""
This is a specification
with one example using injected data ${ (i: Int) => i must_== i }
"""
/** you need to define this method */
def foreach[R : AsResult](commandLine: CommandLine)(f: Int => R) =
AsResult(f(commandLine.int("value").getOrElse(0)))
}
And for a mutable specification:
class SpecificationWithArgs extends mutable.Specification with specification.mutable.ForEachWithCommandLine[Int] {
"This is a specification" >> {
"with one example using injected data" >> { (i: Int) =>
i must_== i
}
}
/** you need to define this method */
def foreach[R : AsResult](commandLine: CommandLine)(f: Int => R) =
AsResult(f(commandLine.int("value").getOrElse(0)))
}