class Test::Runner
The Test::Runner
class handles the execution of tests.
Constants
- KNOWN_FORMATS
List of known report formats.
TODO: Could use finder gem to look these up, but that’s yet another dependency.
- OPEN_ERRORS
Exceptions that are not caught by test runner.
Attributes
Handle all configuration via the config instance.
Array of observers, typically this just contains the recorder and reporter instances.
Record pass, fail, error and pending tests.
The reporter to use for ouput.
Public Class Methods
New Runner
.
@param [Config] config
Config instance.
# File lib/rubytest/runner.rb, line 51 def initialize(config) #:yield: @config = case config when Config then config when Hash then Config.new(config) else Test.configuration(config) end @config.apply! # apply lazy config block yield(@config) if block_given? @advice = Advice.new end
Run tests.
@param [Config,Hash,String,Symbol] config
Either a Config instance, a hash to construct a Config instance with, or a name of a configuration profile.
@return [Boolean] Success of test run.
# File lib/rubytest/runner.rb, line 38 def self.run(config=nil, &config_proc) #:yield: runner = Runner.new(config, &config_proc) runner.run end
Public Instance Methods
Instance of Advice
is a special customizable observer.
# File lib/rubytest/runner.rb, line 92 def advice @advice end
Define universal after advice. Can be used by mock libraries, for example to run mock verification.
# File lib/rubytest/runner.rb, line 103 def after(type, &block) advice.join_after(type, &block) end
Define universal before advice.
# File lib/rubytest/runner.rb, line 97 def before(type, &block) advice.join_before(type, &block) end
Reporter format name, or name fragment, used to look up reporter class.
# File lib/rubytest/runner.rb, line 82 def format config.format end
Run test suite.
@return [Boolean]
That the tests ran without error or failure.
# File lib/rubytest/runner.rb, line 129 def run cd_chdir do Test::Config.load_path_setup if config.autopath? ignore_callers config.loadpath.flatten.each{ |path| $LOAD_PATH.unshift(path) } config.requires.flatten.each{ |file| require file } # Config before advice occurs after loadpath and require are # applied and before test files are required. config.before.call if config.before test_files.each do |test_file| require test_file end @reporter = reporter_load(format) @recorder = Recorder.new @observers = [advice, @recorder, @reporter] observers.each{ |o| o.begin_suite(suite) } run_thru(suite) observers.each{ |o| o.end_suite(suite) } config.after.call if config.after end recorder.success? end
Test
suite to run. This is a list of compliant test units and test cases.
# File lib/rubytest/runner.rb, line 69 def suite config.suite end
TODO: Cache or not?
# File lib/rubytest/runner.rb, line 76 def test_files #@test_files ||= resolve_test_files resolve_test_files end
Define universal upon advice.
See {Advice} for valid join-points.
# File lib/rubytest/runner.rb, line 110 def upon(type, &block) advice.join(type, &block) end
Show extra details in reports.
# File lib/rubytest/runner.rb, line 87 def verbose? config.verbose? end
Private Instance Methods
Change to directory and run block.
@raise [Errno::ENOENT] If directory does not exist.
# File lib/rubytest/runner.rb, line 334 def cd_chdir(&block) if dir = config.chdir unless File.directory?(dir) raise Errno::ENOENT, "change directory doesn't exist -- `#{dir}'" end Dir.chdir(dir, &block) else block.call end end
Add to $RUBY_IGNORE_CALLERS.
@todo Improve on this!
# File lib/rubytest/runner.rb, line 166 def ignore_callers ignore_path = File.expand_path(File.join(__FILE__, '../../..')) ignore_regexp = Regexp.new(Regexp.escape(ignore_path)) $RUBY_IGNORE_CALLERS ||= {} $RUBY_IGNORE_CALLERS << ignore_regexp $RUBY_IGNORE_CALLERS << /bin\/rubytest/ end
Returns a list of available report types.
@return [Array<String>]
The names of available reporters.
# File lib/rubytest/runner.rb, line 310 def reporter_list return KNOWN_FORMATS.sort #list = Dir[File.dirname(__FILE__) + '/reporters/*.rb'] #list = list.map{ |r| File.basename(r).chomp('.rb') } #list = list.reject{ |r| /^abstract/ =~ r } #list.sort end
Get a reporter instance be name fragment.
@return [Reporter::Abstract]
The test reporter instance.
# File lib/rubytest/runner.rb, line 283 def reporter_load(format) format = DEFAULT_REPORT_FORMAT unless format format = format.to_s.downcase name = reporter_list.find{ |r| /^#{format}/ =~ r } || format begin require "rubytest/format/#{name}" rescue LoadError raise "mistyped or uninstalled report format" unless format end reporter = Test::Reporters.const_get(name.capitalize) reporter.new(self) end
Files can be globs and directories which need to be resolved to a list of files.
@return [Array<String>]
# File lib/rubytest/runner.rb, line 322 def resolve_test_files list = config.files.flatten list = list.map{ |f| Dir[f] }.flatten list = list.map{ |f| File.directory?(f) ? Dir[File.join(f, '**/*.rb')] : f } list = list.flatten.uniq list = list.map{ |f| File.expand_path(f) } list end
Run a test case.
# File lib/rubytest/runner.rb, line 190 def run_case(tcase) if tcase.respond_to?(:skip?) && (reason = tcase.skip?) return observers.each{ |o| o.skip_case(tcase, reason) } end observers.each{ |o| o.begin_case(tcase) } if tcase.respond_to?(:call) tcase.call do run_thru( select(tcase) ) end else run_thru( select(tcase) ) end observers.each{ |o| o.end_case(tcase) } end
Run a test.
@param [Object] test
The test to run, must repsond to #call.
# File lib/rubytest/runner.rb, line 213 def run_test(test) if test.respond_to?(:skip?) && (reason = test.skip?) return observers.each{ |o| o.skip_test(test, reason) } end observers.each{ |o| o.begin_test(test) } begin success = test.call if config.hard? && !success # TODO: separate run_test method to speed things up? raise Assertion, "failure of #{test}" else observers.each{ |o| o.pass(test) } end rescue *OPEN_ERRORS => exception raise exception rescue NotImplementedError => exception #if exception.assertion? # TODO: May require assertion? for todo in future observers.each{ |o| o.todo(test, exception) } #else # observers.each{ |o| o.error(test, exception) } #end rescue Exception => exception if exception.assertion? observers.each{ |o| o.fail(test, exception) } else observers.each{ |o| o.error(test, exception) } end end observers.each{ |o| o.end_test(test) } end
# File lib/rubytest/runner.rb, line 176 def run_thru(list) list.each do |t| if t.respond_to?(:each) run_case(t) elsif t.respond_to?(:call) run_test(t) else #run_note(t) ? end end end
Filter cases based on selection criteria.
@return [Array] selected test cases
# File lib/rubytest/runner.rb, line 251 def select(cases) selected = [] if cases.respond_to?(:ordered?) && cases.ordered? cases.each do |tc| selected << tc end else cases.each do |tc| next if tc.respond_to?(:skip?) && tc.skip? next if !config.match.empty? && !config.match.any?{ |m| m =~ tc.to_s } if !config.units.empty? next unless tc.respond_to?(:unit) next unless config.units.find{ |u| tc.unit.start_with?(u) } end if !config.tags.empty? next unless tc.respond_to?(:tags) tc_tags = [tc.tags].flatten.map{ |t| t.to_s } next if (config.tags & tc_tags).empty? end selected << tc end end selected end