diff --git a/src/spectator/command_line_arguments_config_source.cr b/src/spectator/command_line_arguments_config_source.cr index d6933f5..a815096 100644 --- a/src/spectator/command_line_arguments_config_source.cr +++ b/src/spectator/command_line_arguments_config_source.cr @@ -21,8 +21,9 @@ module Spectator parser.on("-e", "--example STRING", "Run examples whose full nested names include STRING") { |pattern| raise NotImplementedError.new("-e") } parser.on("-l", "--line LINE", "Run examples whose line matches LINE") { |line| raise NotImplementedError.new("-l") } parser.on("-p", "--profile", "Display the 10 slowest specs") { raise NotImplementedError.new("-p") } + parser.on("-r", "--rand", "Randomize the execution order of tests") { builder.randomize } + parser.on("--seed INTEGER", "Set the seed for the random number generator (implies -r)") { |seed| builder.randomize; builder.seed = seed.to_i } parser.on("--location FILE:LINE", "Run the example at line 'LINE' in the file 'FILE', multiple allowed") { |location| raise NotImplementedError.new("--location") } - parser.on("--seed INTEGER", "Set the seed for the random number generator") { |seed| builder.seed = seed.to_i } parser.on("--json", "Generate JSON output") { builder.formatter = Formatting::JsonFormatter.new } parser.on("--junit_output OUTPUT_DIR", "Generate JUnit XML output") { |output_dir| builder.add_formatter(Formatting::JUnitFormatter.new(output_dir)) } parser.on("--tap", "Generate TAP output (Test Anything Protocol)") { builder.formatter = Formatting::TAPFormatter.new } diff --git a/src/spectator/config.cr b/src/spectator/config.cr index bd97628..cfecac4 100644 --- a/src/spectator/config.cr +++ b/src/spectator/config.cr @@ -16,6 +16,9 @@ module Spectator # Random number generator to use for everything. getter random : Random + # Indicates whether tests are run in a random order. + getter? randomize : Bool + # Creates a new configuration. def initialize(builder) @formatters = builder.formatters @@ -23,6 +26,7 @@ module Spectator @fail_blank = builder.fail_blank? @dry_run = builder.dry_run? @random = builder.random + @randomize = builder.randomize? end # Yields each formatter that should be reported to. diff --git a/src/spectator/config_builder.cr b/src/spectator/config_builder.cr index 62b3fa9..d6eed76 100644 --- a/src/spectator/config_builder.cr +++ b/src/spectator/config_builder.cr @@ -16,6 +16,7 @@ module Spectator @fail_fast = false @fail_blank = false @dry_run = false + @randomize = false # Sets the primary formatter to use for reporting test progress and results. def formatter=(formatter : Formatting::Formatter) @@ -91,6 +92,22 @@ module Spectator def seed=(seed) @random = Random.new(seed) end + + # Randomizes test execution order. + def randomize + self.randomize = true + end + + # Enables or disables running tests in a random order. + def randomize=(flag) + @randomize = flag + end + + # Indicates whether tests are run in a random order. + def randomize? + @randomize + end + # Creates a configuration. def build : Config Config.new(self) diff --git a/src/spectator/runner.cr b/src/spectator/runner.cr index 83ef37b..2c8e743 100644 --- a/src/spectator/runner.cr +++ b/src/spectator/runner.cr @@ -31,13 +31,24 @@ module Spectator # Runs all examples and adds results to a list. private def collect_results(results) - @suite.each do |example| + example_order.each do |example| result = run_example(example).as(Result) results << result break if @config.fail_fast? && result.is_a?(FailedResult) end end + # Retrieves an enumerable for the examples to run. + # The order of examples is randomized + # if specified by the configuration. + private def example_order + if @config.randomize? + @suite.to_a.shuffle(@config.random) + else + @suite.each + end + end + # Runs a single example and returns the result. # The formatter is given the example and result information. private def run_example(example)