+ Added TestCase.exclude and load_excludes for programmatic filtering of tests.

Refactored unit tests into metametameta to share assert_report, setup, and teardown
[git-p4: depot-paths = "//src/minitest/dev/": change = 6785]
This commit is contained in:
Ryan Davis 2011-12-07 13:10:34 -08:00
parent 4b0fd91d3c
commit fa13094efa
5 changed files with 190 additions and 45 deletions

View File

@ -7,11 +7,15 @@ design_rationale.rb
lib/hoe/minitest.rb
lib/minitest/autorun.rb
lib/minitest/benchmark.rb
lib/minitest/excludes.rb
lib/minitest/mock.rb
lib/minitest/pride.rb
lib/minitest/spec.rb
lib/minitest/unit.rb
test/metametameta.rb
test/test_minitest_benchmark.rb
test/test_minitest_excludes.rb
test/test_minitest_mock.rb
test/test_minitest_spec.rb
test/test_minitest_unit.rb

74
lib/minitest/excludes.rb Normal file
View File

@ -0,0 +1,74 @@
require 'minitest/unit'
##
# minitest/excludes.rb extends MiniTest::Unit::TestCase to provide a
# clean API for excluding certain tests you don't want to run under
# certain conditions.
#
# For example, in test/test_xyz.rb you have:
#
# class TestXYZ < MiniTest::Unit::TestCase
# def test_good
# # test that passes
# end
#
# def test_bad
# # test that fails only on jruby
# end
# end
#
# For jruby runs, you can add test/excludes/TestXYZ.rb with:
#
# exclude :test_bad, "Uses ObjectSpace" if jruby?
#
# The file is instance_eval'd on TestXYZ so you can call the exclude
# class method directly. Since it is ruby you can provide any sort
# of conditions you want to figure out if your tests should be
# excluded.
#
# TestCase.exclude causes test methods to call skip with the reason
# you provide. If you run your tests in verbose mode, you'll see a
# full report of the tests you've excluded.
#
# If you want to change where the exclude files are located, you can
# set the EXCLUDE_DIR environment variable.
class MiniTest::Unit::TestCase
ENV['EXCLUDE_DIR'] ||= "test/excludes"
##
# Exclude a test from a testcase. This is intended to be used by
# exclusion files.
def self.exclude name, reason
return warn "Method #{self}##{name} is not defined" unless
method_defined? name
define_method name do
skip reason
end
end
##
# Loads the exclusion file for the class, if any.
def self.load_excludes
@__load_excludes__ ||=
begin
if name and not name.empty? then
file = File.join ENV['EXCLUDE_DIR'], "#{name}.rb"
instance_eval File.read file if File.exist? file
end
true
end
end
class << self
alias :old_test_methods :test_methods # :nodoc:
def test_methods # :nodoc:
load_excludes
old_test_methods
end
end
end

42
test/metametameta.rb Normal file
View File

@ -0,0 +1,42 @@
require 'tempfile'
require 'stringio'
require 'minitest/autorun'
class MetaMetaMetaTestCase < MiniTest::Unit::TestCase
def assert_report expected = nil
expected ||= <<-EOM.gsub(/^ {6}/, '')
Run options: --seed 42
# Running tests:
.
Finished tests in 0.00
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
EOM
output = @output.string.dup
output.sub!(/Finished tests in .*/, "Finished tests in 0.00")
output.sub!(/Loaded suite .*/, 'Loaded suite blah')
output.gsub!(/(?:.\/)?test\/[^:]+:\d+/, 'FILE:LINE')
output.gsub!(/\[[^\]]+\]/, '[FILE:LINE]')
assert_equal(expected, output)
end
def setup
super
srand 42
MiniTest::Unit::TestCase.reset
@tu = MiniTest::Unit.new
@output = StringIO.new("")
MiniTest::Unit.runner = nil # protect the outer runner from the inner tests
MiniTest::Unit.output = @output
end
def teardown
super
MiniTest::Unit.output = $stdout
Object.send :remove_const, :ATestCase if defined? ATestCase
end
end

View File

@ -0,0 +1,54 @@
require 'test/metametameta'
require 'minitest/excludes'
class TestMiniTestExcludes < MetaMetaMetaTestCase
def test_cls_excludes
srand 42
old_exclude_base = ENV['EXCLUDE_DIR']
@assertion_count = 0
Dir.mktmpdir do |path|
ENV['EXCLUDE_DIR'] = path
File.open File.join(path, "ATestCase.rb"), "w" do |f|
f.puts <<-EOM
exclude :test_test2, "because it is borked"
EOM
end
tc = Class.new(MiniTest::Unit::TestCase) do
def test_test1; assert true end
def test_test2; assert false end # oh noes!
def test_test3; assert true end
end
Object.const_set(:ATestCase, tc)
assert_equal %w(test_test1 test_test2 test_test3), ATestCase.test_methods
@tu.run %w[--seed 42 --verbose]
expected = <<-EOM.gsub(/^ {8}/, '')
Run options: --seed 42 --verbose
# Running tests:
ATestCase#test_test2 = 0.00 s = S
ATestCase#test_test1 = 0.00 s = .
ATestCase#test_test3 = 0.00 s = .
Finished tests in 0.00
1) Skipped:
test_test2(ATestCase) [FILE:LINE]:
because it is borked
3 tests, 2 assertions, 0 failures, 0 errors, 1 skips
EOM
assert_report expected
end
ensure
ENV['EXCLUDE_DIR'] = old_exclude_base
end
end

View File

@ -1,12 +1,11 @@
require 'stringio'
require 'pathname'
require 'minitest/autorun'
require 'test/metametameta'
module MyModule; end
class AnError < StandardError; include MyModule; end
class ImmutableString < String; def inspect; super.freeze; end; end
class TestMiniTestUnit < MiniTest::Unit::TestCase
class TestMiniTestUnit < MetaMetaMetaTestCase
pwd = Pathname.new(File.expand_path(Dir.pwd))
basedir = Pathname.new(File.expand_path("lib/minitest")) + 'mini'
basedir = basedir.relative_path_from(pwd).to_s
@ -16,38 +15,6 @@ class TestMiniTestUnit < MiniTest::Unit::TestCase
"#{MINITEST_BASE_DIR}/test.rb:139:in `run'",
"#{MINITEST_BASE_DIR}/test.rb:106:in `run'"]
def assert_report expected = nil
expected ||= "Run options: --seed 42
# Running tests:
.
Finished tests in 0.00
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
"
output = @output.string.sub(/Finished tests in .*/, "Finished tests in 0.00")
output.sub!(/Loaded suite .*/, 'Loaded suite blah')
output.sub!(/^(\s+)(?:#{Regexp.union(__FILE__, File.expand_path(__FILE__))}):\d+:/o, '\1FILE:LINE:')
output.sub!(/\[(?:#{Regexp.union(__FILE__, File.expand_path(__FILE__))}):\d+\]/o, '[FILE:LINE]')
assert_equal(expected, output)
end
def setup
srand 42
MiniTest::Unit::TestCase.reset
@tu = MiniTest::Unit.new
@output = StringIO.new("")
MiniTest::Unit.runner = nil # protect the outer runner from the inner tests
MiniTest::Unit.output = @output
end
def teardown
MiniTest::Unit.output = $stdout
Object.send :remove_const, :ATestCase if defined? ATestCase
end
def test_class_puke_with_assertion_failed
exception = MiniTest::Assertion.new "Oh no!"
exception.set_backtrace ["unhappy"]
@ -229,21 +196,23 @@ Finished tests in 0.00
@tu.run %w[--seed 42]
expected = "Run options: --seed 42
expected = <<-EOM.gsub(/^ {6}/, '')
Run options: --seed 42
# Running tests:
# Running tests:
E.
E.
Finished tests in 0.00
Finished tests in 0.00
1) Error:
test_error(ATestCase):
RuntimeError: unhandled exception
FILE:LINE:in `test_error'
1) Error:
test_error(ATestCase):
RuntimeError: unhandled exception
FILE:LINE:in `test_error'
2 tests, 1 assertions, 0 failures, 1 errors, 0 skips
EOM
2 tests, 1 assertions, 0 failures, 1 errors, 0 skips
"
assert_report expected
end
@ -621,6 +590,8 @@ end
class TestMiniTestUnitTestCase < MiniTest::Unit::TestCase
def setup
super
MiniTest::Unit::TestCase.reset
@tc = MiniTest::Unit::TestCase.new 'fake tc'