Imported minitest 2.5.0 (r6557)

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@33036 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ryan 2011-08-23 21:47:25 +00:00
parent 885f5fa2b0
commit 2c43b9664b
9 changed files with 1085 additions and 248 deletions

View File

@ -1,3 +1,8 @@
Wed Aug 24 06:45:20 2011 Ryan Davis <ryand-ruby@zenspider.com>
* lib/minitest/*: Imported minitest 2.5.0 (r6557)
* test/minitest/*: ditto
Wed Aug 24 00:38:22 2011 Yusuke Endoh <mame@tsg.ne.jp>
* thread.c (update_coverage): skip coverage count up if the current

270
lib/minitest/README.txt Normal file
View File

@ -0,0 +1,270 @@
= minitest/{unit,spec,mock,benchmark}
home :: https://github.com/seattlerb/minitest
rdoc :: http://bfts.rubyforge.org/minitest
== DESCRIPTION:
minitest provides a complete suite of testing facilities supporting
TDD, BDD, mocking, and benchmarking.
minitest/unit is a small and incredibly fast unit testing framework.
It provides a rich set of assertions to make your tests clean and
readable.
minitest/spec is a functionally complete spec engine. It hooks onto
minitest/unit and seamlessly bridges test assertions over to spec
expectations.
minitest/benchmark is an awesome way to assert the performance of your
algorithms in a repeatable manner. Now you can assert that your newb
co-worker doesn't replace your linear algorithm with an exponential
one!
minitest/mock by Steven Baker, is a beautifully tiny mock object
framework.
minitest/pride shows pride in testing and adds coloring to your test
output. I guess it is an example of how to write IO pipes too. :P
minitest/unit is meant to have a clean implementation for language
implementors that need a minimal set of methods to bootstrap a working
test suite. For example, there is no magic involved for test-case
discovery.
== FEATURES/PROBLEMS:
* minitest/autorun - the easy and explicit way to run all your tests.
* minitest/unit - a very fast, simple, and clean test system.
* minitest/spec - a very fast, simple, and clean spec system.
* minitest/mock - a simple and clean mock system.
* minitest/benchmark - an awesome way to assert your algorithm's performance.
* minitest/pride - show your pride in testing!
* Incredibly small and fast runner, but no bells and whistles.
== RATIONALE:
See design_rationale.rb to see how specs and tests work in minitest.
== SYNOPSIS:
Given that you'd like to test the following class:
class Meme
def i_can_has_cheezburger?
"OHAI!"
end
def will_it_blend?
"YES!"
end
end
=== Unit tests
require 'minitest/autorun'
class TestMeme < MiniTest::Unit::TestCase
def setup
@meme = Meme.new
end
def test_that_kitty_can_eat
assert_equal "OHAI!", @meme.i_can_has_cheezburger?
end
def test_that_it_will_not_blend
refute_match /^no/i, @meme.will_it_blend?
end
end
=== Specs
require 'minitest/autorun'
describe Meme do
before do
@meme = Meme.new
end
describe "when asked about cheeseburgers" do
it "must respond positively" do
@meme.i_can_has_cheezburger?.must_equal "OHAI!"
end
end
describe "when asked about blending possibilities" do
it "won't say no" do
@meme.will_it_blend?.wont_match /^no/i
end
end
end
=== Benchmarks
Add benchmarks to your regular unit tests. If the unit tests fail, the
benchmarks won't run.
# optionally run benchmarks, good for CI-only work!
require 'minitest/benchmark' if ENV["BENCH"]
class TestMeme < MiniTest::Unit::TestCase
# Override self.bench_range or default range is [1, 10, 100, 1_000, 10_000]
def bench_my_algorithm
assert_performance_linear 0.9999 do |n| # n is a range value
n.times do
@obj.my_algorithm
end
end
end
end
Or add them to your specs. If you make benchmarks optional, you'll
need to wrap your benchmarks in a conditional since the methods won't
be defined.
describe Meme do
if ENV["BENCH"] then
bench_performance_linear "my_algorithm", 0.9999 do |n|
100.times do
@obj.my_algorithm(n)
end
end
end
end
outputs something like:
# Running benchmarks:
TestBlah 100 1000 10000
bench_my_algorithm 0.006167 0.079279 0.786993
bench_other_algorithm 0.061679 0.792797 7.869932
Output is tab-delimited to make it easy to paste into a spreadsheet.
=== Mocks
class MemeAsker
def initialize(meme)
@meme = meme
end
def ask(question)
method = question.tr(" ","_") + "?"
@meme.send(method)
end
end
require 'minitest/autorun'
describe MemeAsker do
before do
@meme = MiniTest::Mock.new
@meme_asker = MemeAsker.new @meme
end
describe "#ask" do
describe "when passed an unpunctuated question" do
it "should invoke the appropriate predicate method on the meme" do
@meme.expect :will_it_blend?, :return_value
@meme_asker.ask "will it blend"
@meme.verify
end
end
end
end
=== Customizable Test Runner Types:
MiniTest::Unit.runner=(runner) provides an easy way of creating custom
test runners for specialized needs. Justin Weiss provides the
following real-world example to create an alternative to regular
fixture loading:
class MiniTestWithHooks::Unit < MiniTest::Unit
def before_suites
end
def after_suites
end
def _run_suites(suites, type)
begin
before_suites
super(suites, type)
ensure
after_suites
end
end
def _run_suite(suite, type)
begin
suite.before_suite
super(suite, type)
ensure
suite.after_suite
end
end
end
module MiniTestWithTransactions
class Unit < MiniTestWithHooks::Unit
include TestSetupHelper
def before_suites
super
setup_nested_transactions
# load any data we want available for all tests
end
def after_suites
teardown_nested_transactions
super
end
end
end
MiniTest::Unit.runner = MiniTestWithTransactions::Unit.new
== REQUIREMENTS:
* Ruby 1.8, maybe even 1.6 or lower. No magic is involved.
== INSTALL:
sudo gem install minitest
On 1.9, you already have it. To get newer candy you can still install
the gem, but you'll need to activate the gem explicitly to use it:
require 'rubygems'
gem 'minitest' # ensures you're using the gem, and not the built in MT
require 'minitest/autorun'
# ... usual testing stuffs ...
== LICENSE:
(The MIT License)
Copyright (c) Ryan Davis, seattle.rb
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -15,20 +15,39 @@ module MiniTest
# All mock objects are an instance of Mock
class Mock
alias :__respond_to? :respond_to?
skip_methods = %w(object_id respond_to_missing? inspect === to_s)
instance_methods.each do |m|
undef_method m unless skip_methods.include?(m.to_s) || m =~ /^__/
end
def initialize # :nodoc:
@expected_calls = {}
@actual_calls = Hash.new {|h,k| h[k] = [] }
end
##
# Expect that method +name+ is called, optionally with +args+, and
# returns +retval+.
# Expect that method +name+ is called, optionally with +args+, and returns
# +retval+.
#
# @mock.expect(:meaning_of_life, 42)
# @mock.meaning_of_life # => 42
#
# @mock.expect(:do_something_with, true, [some_obj, true])
# @mock.do_something_with(some_obj, true) # => true
#
# +args+ is compared to the expected args using case equality (ie, the
# '===' operator), allowing for less specific expectations.
#
# @mock.expect(:uses_any_string, true, [String])
# @mock.uses_any_string("foo") # => true
# @mock.verify # => true
#
# @mock.expect(:uses_one_string, true, ["foo"]
# @mock.uses_one_string("bar") # => true
# @mock.verify # => raises MockExpectationError
def expect(name, retval, args=[])
@expected_calls[name] = { :retval => retval, :args => args }
@ -43,25 +62,45 @@ module MiniTest
def verify
@expected_calls.each_key do |name|
expected = @expected_calls[name]
msg = "expected #{name}, #{expected.inspect}"
raise MockExpectationError, msg unless
msg1 = "expected #{name}, #{expected.inspect}"
msg2 = "#{msg1}, got #{@actual_calls[name].inspect}"
raise MockExpectationError, msg2 if
@actual_calls.has_key? name and
not @actual_calls[name].include?(expected)
raise MockExpectationError, msg1 unless
@actual_calls.has_key? name and @actual_calls[name].include?(expected)
end
true
end
def method_missing(sym, *args) # :nodoc:
raise NoMethodError unless @expected_calls.has_key?(sym)
raise ArgumentError unless @expected_calls[sym][:args].size == args.size
retval = @expected_calls[sym][:retval]
@actual_calls[sym] << { :retval => retval, :args => args }
expected = @expected_calls[sym]
unless expected then
raise NoMethodError, "unmocked method %p, expected one of %p" %
[sym, @expected_calls.keys.sort_by(&:to_s)]
end
expected_args, retval = expected[:args], expected[:retval]
unless expected_args.size == args.size
raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
[sym, expected[:args].size, args.size]
end
@actual_calls[sym] << {
:retval => retval,
:args => expected_args.zip(args).map { |mod, a| mod if mod === a }
}
retval
end
alias :original_respond_to? :respond_to?
def respond_to?(sym) # :nodoc:
return true if @expected_calls.has_key?(sym)
return original_respond_to?(sym)
return __respond_to?(sym)
end
end
end

View File

@ -10,32 +10,90 @@ require "minitest/unit"
# Show your testing pride!
class PrideIO
attr_reader :io
ESC = "\e["
NND = "#{ESC}0m"
# stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
COLORS = (31..36).to_a
CHARS = ["*"]
attr_reader :io
def initialize io
@io = io
@colors = COLORS.cycle
@chars = CHARS.cycle
# stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
# also reference http://en.wikipedia.org/wiki/ANSI_escape_code
@colors ||= (31..36).to_a
@size = @colors.size
@index = 0
# io.sync = true
end
def print o
case o
when "." then
io.print "\e[#{@colors.next}m#{@chars.next}\e[0m"
io.print pride o
when "E", "F" then
io.print "\e[41m\e[37m#{o}\e[0m"
io.print "#{ESC}41m#{ESC}37m#{o}#{NND}"
else
io.print o
end
end
def puts(*o)
o.map! { |s|
s.sub(/Finished tests/) {
@index = 0
'Fabulous tests'.split(//).map { |c|
pride(c)
}.join
}
}
super
end
def pride string
string = "*" if string == "."
c = @colors[@index % @size]
@index += 1
"#{ESC}#{c}m#{string}#{NND}"
end
def method_missing msg, *args
io.send(msg, *args)
end
end
MiniTest::Unit.output = PrideIO.new(MiniTest::Unit.output)
class PrideLOL < PrideIO # inspired by lolcat, but massively cleaned up
PI_3 = Math::PI / 3
def initialize io
# walk red, green, and blue around a circle separated by equal thirds.
#
# To visualize, type this into wolfram-alpha:
#
# plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3)
# 6 has wide pretty gradients. 3 == lolcat, about half the width
@colors = (0...(6 * 7)).map { |n|
n *= 1.0 / 6
r = (3 * Math.sin(n ) + 3).to_i
g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i
# Then we take rgb and encode them in a single number using base 6.
# For some mysterious reason, we add 16... to clear the bottom 4 bits?
# Yes... they're ugly.
36 * r + 6 * g + b + 16
}
super
end
def pride string
c = @colors[@index % @size]
@index += 1
"#{ESC}38;5;#{c}m#{string}#{NND}"
end
end
klass = ENV['TERM'] =~ /^xterm(-256color)?$/ ? PrideLOL : PrideIO
MiniTest::Unit.output = klass.new(MiniTest::Unit.output)

View File

@ -8,7 +8,7 @@
require 'minitest/unit'
class Module
class Module # :nodoc:
def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
# warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
self.class_eval <<-EOM
@ -23,39 +23,18 @@ class Module
end
##
# Create your own expectations from MiniTest::Assertions using a
# flexible set of rules. If you don't like must/wont, then this
# method is your friend. For an example of its usage see the bottom
# of minitest/spec.rb.
# infect_with_assertions has been removed due to excessive clever.
# Use infect_an_assertion directly instead.
def infect_with_assertions(pos_prefix, neg_prefix,
skip_re,
dont_flip_re = /\c0/,
map = {})
MiniTest::Assertions.public_instance_methods(false).sort.each do |meth|
meth = meth.to_s
new_name = case meth
when /^assert/ then
meth.sub(/^assert/, pos_prefix.to_s)
when /^refute/ then
meth.sub(/^refute/, neg_prefix.to_s)
end
next unless new_name
next if new_name =~ skip_re
regexp, replacement = map.find { |re, _| new_name =~ re }
new_name.sub! regexp, replacement if replacement
puts "\n##\n# :method: #{new_name}\n# See MiniTest::Assertions##{meth}" if
$0 == __FILE__
infect_an_assertion meth, new_name, new_name =~ dont_flip_re
end
abort "infect_with_assertions is dead. Use infect_an_assertion directly"
end
end
module Kernel
module Kernel # :nodoc:
##
# Describe a series of expectations for a given target +desc+.
#
@ -80,25 +59,16 @@ module Kernel
# end
# end
def describe desc, &block # :doc:
def describe desc, additional_desc = nil, &block # :doc:
stack = MiniTest::Spec.describe_stack
name = [stack.last, desc].compact.join("::")
name = [stack.last, desc, additional_desc].compact.join("::")
sclas = stack.last || if Class === self && self < MiniTest::Spec then
self
else
MiniTest::Spec.spec_type desc
end
cls = Class.new sclas
sclas.children << cls unless cls == MiniTest::Spec
# :stopdoc:
# omg this sucks
(class << cls; self; end).send(:define_method, :to_s) { name }
(class << cls; self; end).send(:define_method, :desc) { desc }
# :startdoc:
cls.nuke_test_methods!
cls = sclas.create name, desc
stack.push cls
cls.class_eval(&block)
@ -111,7 +81,7 @@ end
##
# MiniTest::Spec -- The faster, better, less-magical spec framework!
#
# For a list of expectations, see Object.
# For a list of expectations, see MiniTest::Expectations.
class MiniTest::Spec < MiniTest::Unit::TestCase
##
@ -151,6 +121,9 @@ class MiniTest::Spec < MiniTest::Unit::TestCase
@@current_spec
end
##
# Returns the children of this spec.
def self.children
@children ||= []
end
@ -166,25 +139,6 @@ class MiniTest::Spec < MiniTest::Unit::TestCase
end
end
##
# Spec users want setup/teardown to be inherited and NOTHING ELSE.
# It is almost like method reuse is lost on them.
def self.define_inheritable_method name, &block # :nodoc:
# regular super() warns
super_method = self.superclass.instance_method name
teardown = name.to_s == "teardown"
super_before = super_method && ! teardown
super_after = super_method && teardown
define_method name do
super_method.bind(self).call if super_before
instance_eval(&block)
super_method.bind(self).call if super_after
end
end
##
# Define a 'before' action. Inherits the way normal methods should.
#
@ -194,7 +148,8 @@ class MiniTest::Spec < MiniTest::Unit::TestCase
def self.before type = :each, &block
raise "unsupported before type: #{type}" unless type == :each
define_inheritable_method :setup, &block
add_setup_hook {|tc| tc.instance_eval(&block) }
end
##
@ -206,7 +161,8 @@ class MiniTest::Spec < MiniTest::Unit::TestCase
def self.after type = :each, &block
raise "unsupported after type: #{type}" unless type == :each
define_inheritable_method :teardown, &block
add_teardown_hook {|tc| tc.instance_eval(&block) }
end
##
@ -232,154 +188,311 @@ class MiniTest::Spec < MiniTest::Unit::TestCase
mod.send :undef_method, name if mod.public_method_defined? name
end
end
end
Object.infect_with_assertions(:must, :wont,
/^(must|wont)$|wont_(throw)|
must_(block|not?_|nothing|raise$)/x,
/(must|wont)_(include|respond_to)/,
/(must_throw)s/ => '\1',
/(?!not)_same/ => '_be_same_as',
/_in_/ => '_be_within_',
/_operator/ => '_be',
/_includes/ => '_include',
/(must|wont)_(.*_of|nil|silent|empty)/ => '\1_be_\2',
/must_raises/ => 'must_raise')
class Object
alias :must_be_close_to :must_be_within_delta
alias :wont_be_close_to :wont_be_within_delta
if $0 == __FILE__ then
{ "must" => "assert", "wont" => "refute" }.each do |a, b|
puts "\n"
puts "##"
puts "# :method: #{a}_be_close_to"
puts "# See MiniTest::Assertions##{b}_in_delta"
def self.let name, &block
define_method name do
@_memoized ||= {}
@_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) }
end
end
##
# :method: must_be
# See MiniTest::Assertions#assert_operator
def self.subject &block
let :subject, &block
end
##
# :method: must_be_close_to
# See MiniTest::Assertions#assert_in_delta
def self.create name, desc # :nodoc:
cls = Class.new(self) do
@name = name
@desc = desc
##
# :method: must_be_empty
# See MiniTest::Assertions#assert_empty
nuke_test_methods!
end
##
# :method: must_be_instance_of
# See MiniTest::Assertions#assert_instance_of
children << cls
##
# :method: must_be_kind_of
# See MiniTest::Assertions#assert_kind_of
cls
end
##
# :method: must_be_nil
# See MiniTest::Assertions#assert_nil
def self.to_s # :nodoc:
defined?(@name) ? @name : super
end
##
# :method: must_be_same_as
# See MiniTest::Assertions#assert_same
##
# :method: must_be_silent
# See MiniTest::Assertions#assert_silent
##
# :method: must_be_within_delta
# See MiniTest::Assertions#assert_in_delta
##
# :method: must_be_within_epsilon
# See MiniTest::Assertions#assert_in_epsilon
##
# :method: must_equal
# See MiniTest::Assertions#assert_equal
##
# :method: must_include
# See MiniTest::Assertions#assert_includes
##
# :method: must_match
# See MiniTest::Assertions#assert_match
##
# :method: must_output
# See MiniTest::Assertions#assert_output
##
# :method: must_raise
# See MiniTest::Assertions#assert_raises
##
# :method: must_respond_to
# See MiniTest::Assertions#assert_respond_to
##
# :method: must_send
# See MiniTest::Assertions#assert_send
##
# :method: must_throw
# See MiniTest::Assertions#assert_throws
##
# :method: wont_be
# See MiniTest::Assertions#refute_operator
##
# :method: wont_be_close_to
# See MiniTest::Assertions#refute_in_delta
##
# :method: wont_be_empty
# See MiniTest::Assertions#refute_empty
##
# :method: wont_be_instance_of
# See MiniTest::Assertions#refute_instance_of
##
# :method: wont_be_kind_of
# See MiniTest::Assertions#refute_kind_of
##
# :method: wont_be_nil
# See MiniTest::Assertions#refute_nil
##
# :method: wont_be_same_as
# See MiniTest::Assertions#refute_same
##
# :method: wont_be_within_delta
# See MiniTest::Assertions#refute_in_delta
##
# :method: wont_be_within_epsilon
# See MiniTest::Assertions#refute_in_epsilon
##
# :method: wont_equal
# See MiniTest::Assertions#refute_equal
##
# :method: wont_include
# See MiniTest::Assertions#refute_includes
##
# :method: wont_match
# See MiniTest::Assertions#refute_match
##
# :method: wont_respond_to
# See MiniTest::Assertions#refute_respond_to
# :stopdoc:
class << self
attr_reader :name, :desc
end
# :startdoc:
end
module MiniTest::Expectations
##
# See MiniTest::Assertions#assert_empty.
#
# collection.must_be_empty
#
# :method: must_be_empty
infect_an_assertion :assert_empty, :must_be_empty
##
# See MiniTest::Assertions#assert_equal
#
# a.must_equal b
#
# :method: must_equal
infect_an_assertion :assert_equal, :must_equal
##
# See MiniTest::Assertions#assert_in_delta
#
# n.must_be_close_to m [, delta]
#
# :method: must_be_within_delta
infect_an_assertion :assert_in_delta, :must_be_close_to
alias :must_be_within_delta :must_be_close_to
##
# See MiniTest::Assertions#assert_in_epsilon
#
# n.must_be_within_epsilon m [, epsilon]
#
# :method: must_be_within_epsilon
infect_an_assertion :assert_in_epsilon, :must_be_within_epsilon
##
# See MiniTest::Assertions#assert_includes
#
# collection.must_include obj
#
# :method: must_include
infect_an_assertion :assert_includes, :must_include, :reverse
##
# See MiniTest::Assertions#assert_instance_of
#
# obj.must_be_instance_of klass
#
# :method: must_be_instance_of
infect_an_assertion :assert_instance_of, :must_be_instance_of
##
# See MiniTest::Assertions#assert_kind_of
#
# obj.must_be_kind_of mod
#
# :method: must_be_kind_of
infect_an_assertion :assert_kind_of, :must_be_kind_of
##
# See MiniTest::Assertions#assert_match
#
# a.must_match b
#
# :method: must_match
infect_an_assertion :assert_match, :must_match
##
# See MiniTest::Assertions#assert_nil
#
# obj.must_be_nil
#
# :method: must_be_nil
infect_an_assertion :assert_nil, :must_be_nil
##
# See MiniTest::Assertions#assert_operator
#
# n.must_be :<=, 42
#
# :method: must_be
infect_an_assertion :assert_operator, :must_be
##
# See MiniTest::Assertions#assert_output
#
# proc { ... }.must_output out_or_nil [, err]
#
# :method: must_output
infect_an_assertion :assert_output, :must_output
##
# See MiniTest::Assertions#assert_raises
#
# proc { ... }.must_raise exception
#
# :method: must_raise
infect_an_assertion :assert_raises, :must_raise
##
# See MiniTest::Assertions#assert_respond_to
#
# obj.must_respond_to msg
#
# :method: must_respond_to
infect_an_assertion :assert_respond_to, :must_respond_to, :reverse
##
# See MiniTest::Assertions#assert_same
#
# a.must_be_same_as b
#
# :method: must_be_same_as
infect_an_assertion :assert_same, :must_be_same_as
##
# See MiniTest::Assertions#assert_send
# TODO: remove me
#
# a.must_send
#
# :method: must_send
infect_an_assertion :assert_send, :must_send
##
# See MiniTest::Assertions#assert_silent
#
# proc { ... }.must_be_silent
#
# :method: must_be_silent
infect_an_assertion :assert_silent, :must_be_silent
##
# See MiniTest::Assertions#assert_throws
#
# proc { ... }.must_throw sym
#
# :method: must_throw
infect_an_assertion :assert_throws, :must_throw
##
# See MiniTest::Assertions#refute_empty
#
# collection.wont_be_empty
#
# :method: wont_be_empty
infect_an_assertion :refute_empty, :wont_be_empty
##
# See MiniTest::Assertions#refute_equal
#
# a.wont_equal b
#
# :method: wont_equal
infect_an_assertion :refute_equal, :wont_equal
##
# See MiniTest::Assertions#refute_in_delta
#
# n.wont_be_close_to m [, delta]
#
# :method: wont_be_within_delta
infect_an_assertion :refute_in_delta, :wont_be_within_delta
alias :wont_be_close_to :wont_be_within_delta
# FIX: reverse aliases
##
# See MiniTest::Assertions#refute_in_epsilon
#
# n.wont_be_within_epsilon m [, epsilon]
#
# :method: wont_be_within_epsilon
infect_an_assertion :refute_in_epsilon, :wont_be_within_epsilon
##
# See MiniTest::Assertions#refute_includes
#
# collection.wont_include obj
#
# :method: wont_include
infect_an_assertion :refute_includes, :wont_include, :reverse
##
# See MiniTest::Assertions#refute_instance_of
#
# obj.wont_be_instance_of klass
#
# :method: wont_be_instance_of
infect_an_assertion :refute_instance_of, :wont_be_instance_of
##
# See MiniTest::Assertions#refute_kind_of
#
# obj.wont_be_kind_of mod
#
# :method: wont_be_kind_of
infect_an_assertion :refute_kind_of, :wont_be_kind_of
##
# See MiniTest::Assertions#refute_match
#
# a.wont_match b
#
# :method: wont_match
infect_an_assertion :refute_match, :wont_match
##
# See MiniTest::Assertions#refute_nil
#
# obj.wont_be_nil
#
# :method: wont_be_nil
infect_an_assertion :refute_nil, :wont_be_nil
##
# See MiniTest::Assertions#refute_operator
#
# n.wont_be :<=, 42
#
# :method: wont_be
infect_an_assertion :refute_operator, :wont_be
##
# See MiniTest::Assertions#refute_respond_to
#
# obj.wont_respond_to msg
#
# :method: wont_respond_to
infect_an_assertion :refute_respond_to, :wont_respond_to, :reverse
##
# See MiniTest::Assertions#refute_same
#
# a.wont_be_same_as b
#
# :method: wont_be_same_as
infect_an_assertion :refute_same, :wont_be_same_as
end
class Object
include MiniTest::Expectations
end

View File

@ -152,7 +152,7 @@ module MiniTest
def mu_pp obj
s = obj.inspect
s = s.force_encoding Encoding.default_external if defined? Encoding
s = s.encode Encoding.default_external if defined? Encoding
s
end
@ -491,7 +491,7 @@ module MiniTest
# Fails if +obj+ is empty.
def refute_empty obj, msg = nil
msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
assert_respond_to obj, :empty?
refute obj.empty?, msg
end
@ -577,7 +577,7 @@ module MiniTest
end
##
# Fails if +o1+ is not +op+ +o2+ nil. eg:
# Fails if +o1+ is not +op+ +o2+. Eg:
#
# refute_operator 1, :>, 2 #=> pass
# refute_operator 1, :<, 2 #=> fail
@ -620,7 +620,7 @@ module MiniTest
end
class Unit
VERSION = "2.2.2" # :nodoc:
VERSION = "2.5.0" # :nodoc:
attr_accessor :report, :failures, :errors, :skips # :nodoc:
attr_accessor :test_count, :assertion_count # :nodoc:
@ -945,6 +945,7 @@ module MiniTest
begin
@passed = nil
self.setup
self.run_setup_hooks
self.__send__ self.__name__
result = "." unless io?
@passed = true
@ -955,6 +956,7 @@ module MiniTest
result = runner.puke self.class, self.__name__, e
ensure
begin
self.run_teardown_hooks
self.teardown
rescue *PASSTHROUGH_EXCEPTIONS
raise
@ -987,16 +989,24 @@ module MiniTest
reset
def self.inherited klass # :nodoc:
@@test_suites[klass] = true
##
# Call this at the top of your tests when you absolutely
# positively need to have ordered tests. In doing so, you're
# admitting that you suck and your tests are weak.
def self.i_suck_and_my_tests_are_order_dependent!
class << self
define_method :test_order do :alpha end
end
end
##
# Defines test order and is subclassable. Defaults to :random
# but can be overridden to return :alpha if your tests are order
# dependent (read: weak).
def self.inherited klass # :nodoc:
@@test_suites[klass] = true
klass.reset_setup_teardown_hooks
super
end
def self.test_order
def self.test_order # :nodoc:
:random
end
@ -1035,6 +1045,111 @@ module MiniTest
def teardown; end
def self.reset_setup_teardown_hooks # :nodoc:
@setup_hooks = []
@teardown_hooks = []
end
reset_setup_teardown_hooks
##
# Adds a block of code that will be executed before every TestCase is
# run. Equivalent to +setup+, but usable multiple times and without
# re-opening any classes.
#
# All of the setup hooks will run in order after the +setup+ method, if
# one is defined.
#
# The argument can be any object that responds to #call or a block.
# That means that this call,
#
# MiniTest::TestCase.add_setup_hook { puts "foo" }
#
# ... is equivalent to:
#
# module MyTestSetup
# def call
# puts "foo"
# end
# end
#
# MiniTest::TestCase.add_setup_hook MyTestSetup
#
# The blocks passed to +add_setup_hook+ take an optional parameter that
# will be the TestCase instance that is executing the block.
def self.add_setup_hook arg=nil, &block
hook = arg || block
@setup_hooks << hook
end
def self.setup_hooks # :nodoc:
if superclass.respond_to? :setup_hooks then
superclass.setup_hooks
else
[]
end + @setup_hooks
end
def run_setup_hooks # :nodoc:
self.class.setup_hooks.each do |hook|
if hook.respond_to?(:arity) && hook.arity == 1
hook.call(self)
else
hook.call
end
end
end
##
# Adds a block of code that will be executed after every TestCase is
# run. Equivalent to +teardown+, but usable multiple times and without
# re-opening any classes.
#
# All of the teardown hooks will run in reverse order after the
# +teardown+ method, if one is defined.
#
# The argument can be any object that responds to #call or a block.
# That means that this call,
#
# MiniTest::TestCase.add_teardown_hook { puts "foo" }
#
# ... is equivalent to:
#
# module MyTestTeardown
# def call
# puts "foo"
# end
# end
#
# MiniTest::TestCase.add_teardown_hook MyTestTeardown
#
# The blocks passed to +add_teardown_hook+ take an optional parameter
# that will be the TestCase instance that is executing the block.
def self.add_teardown_hook arg=nil, &block
hook = arg || block
@teardown_hooks << hook
end
def self.teardown_hooks # :nodoc:
if superclass.respond_to? :teardown_hooks then
superclass.teardown_hooks
else
[]
end + @teardown_hooks
end
def run_teardown_hooks # :nodoc:
self.class.teardown_hooks.reverse.each do |hook|
if hook.respond_to?(:arity) && hook.arity == 1
hook.call(self)
else
hook.call
end
end
end
include MiniTest::Assertions
end # class TestCase
end # class Unit

View File

@ -49,20 +49,34 @@ class TestMiniTestMock < MiniTest::Unit::TestCase
util_verify_bad
end
def test_not_verify_if_unexpected_method_is_called
assert_raises NoMethodError do
@mock.unexpected
end
end
def test_blow_up_on_wrong_number_of_arguments
@mock.foo
@mock.meaning_of_life
@mock.expect(:sum, 3, [1, 2])
assert_raises ArgumentError do
e = assert_raises ArgumentError do
@mock.sum
end
assert_equal "mocked method :sum expects 2 arguments, got 0", e.message
end
def test_return_mock_does_not_raise
retval = MiniTest::Mock.new
mock = MiniTest::Mock.new
mock.expect(:foo, retval)
mock.foo
assert mock.verify
end
def test_mock_args_does_not_raise
arg = MiniTest::Mock.new
mock = MiniTest::Mock.new
mock.expect(:foo, nil, [arg])
mock.foo(arg)
assert mock.verify
end
def test_blow_up_on_wrong_arguments
@ -81,18 +95,22 @@ class TestMiniTestMock < MiniTest::Unit::TestCase
end
def test_no_method_error_on_unexpected_methods
assert_raises NoMethodError do
e = assert_raises NoMethodError do
@mock.bar
end
expected = "unmocked method :bar, expected one of [:foo, :meaning_of_life]"
assert_equal expected, e.message
end
def test_assign_per_mock_return_values
a = MiniTest::Mock.new
b = MiniTest::Mock.new
a.expect(:foo, :a)
b.expect(:foo, :b)
assert_equal :a, a.foo
assert_equal :b, b.foo
end
@ -104,6 +122,30 @@ class TestMiniTestMock < MiniTest::Unit::TestCase
assert !MiniTest::Mock.new.respond_to?(:foo)
end
def test_mock_is_a_blank_slate
@mock.expect :kind_of?, true, [Fixnum]
@mock.expect :==, true, [1]
assert @mock.kind_of?(Fixnum), "didn't mock :kind_of\?"
assert @mock == 1, "didn't mock :=="
end
def test_verify_allows_called_args_to_be_loosely_specified
mock = MiniTest::Mock.new
mock.expect :loose_expectation, true, [Integer]
mock.loose_expectation 1
assert mock.verify
end
def test_verify_raises_with_strict_args
mock = MiniTest::Mock.new
mock.expect :strict_expectation, true, [2]
mock.strict_expectation 1
util_verify_bad
end
def util_verify_bad
assert_raises MockExpectationError do
@mock.verify

View File

@ -4,11 +4,9 @@
# File a patch instead and assign it to Ryan Davis.
######################################################################
require 'minitest/spec'
require 'minitest/autorun'
require 'stringio'
MiniTest::Unit.autorun
describe MiniTest::Spec do
before do
@assertion_count = 4
@ -202,6 +200,53 @@ describe MiniTest::Spec do
end
end
describe MiniTest::Spec, :let do
i_suck_and_my_tests_are_order_dependent!
def _count
$let_count ||= 0
end
let :count do
$let_count += 1
$let_count
end
it "is evaluated once per example" do
_count.must_equal 0
count.must_equal 1
count.must_equal 1
_count.must_equal 1
end
it "is REALLY evaluated once per example" do
_count.must_equal 1
count.must_equal 2
count.must_equal 2
_count.must_equal 2
end
end
describe MiniTest::Spec, :subject do
attr_reader :subject_evaluation_count
subject do
@subject_evaluation_count ||= 0
@subject_evaluation_count += 1
@subject_evaluation_count
end
it "is evaluated once per example" do
subject.must_equal 1
subject.must_equal 1
subject_evaluation_count.must_equal 1
end
end
class TestMeta < MiniTest::Unit::TestCase
def test_setup
srand 42
@ -245,8 +290,8 @@ class TestMeta < MiniTest::Unit::TestCase
assert_equal "inner thingy", y.desc
assert_equal "very inner thingy", z.desc
top_methods = %w(setup teardown test_0001_top_level_it)
inner_methods = %w(setup teardown test_0001_inner_it)
top_methods = %w(test_0001_top_level_it)
inner_methods = %w(test_0001_inner_it)
assert_equal top_methods, x.instance_methods(false).sort.map {|o| o.to_s }
assert_equal inner_methods, y.instance_methods(false).sort.map {|o| o.to_s }
@ -257,8 +302,9 @@ class TestMeta < MiniTest::Unit::TestCase
_, _, z, before_list, after_list = util_structure
tc = z.new(nil)
tc.setup
tc.teardown
tc.run_setup_hooks
tc.run_teardown_hooks
assert_equal [1, 2, 3], before_list
assert_equal [3, 2, 1], after_list

View File

@ -12,6 +12,7 @@ MiniTest::Unit.autorun
module MyModule; end
class AnError < StandardError; include MyModule; end
class ImmutableString < String; def inspect; super.freeze; end; end
class TestMiniTestUnit < MiniTest::Unit::TestCase
pwd = Pathname.new(File.expand_path(Dir.pwd))
@ -46,12 +47,12 @@ Finished tests in 0.00
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
MiniTest::Unit.runner = nil
Object.send :remove_const, :ATestCase if defined? ATestCase
end
@ -442,6 +443,149 @@ Finished tests in 0.00
assert_report expected
end
def with_overridden_include
Class.class_eval do
def inherited_with_hacks klass
throw :inherited_hook
end
alias inherited_without_hacks inherited
alias inherited inherited_with_hacks
alias IGNORE_ME! inherited # 1.8 bug. god I love venture bros
end
yield
ensure
Class.class_eval do
alias inherited inherited_without_hacks
undef_method :inherited_with_hacks
undef_method :inherited_without_hacks
end
refute_respond_to Class, :inherited_with_hacks
refute_respond_to Class, :inherited_without_hacks
end
def test_inherited_hook_plays_nice_with_others
with_overridden_include do
assert_throws :inherited_hook do
Class.new MiniTest::Unit::TestCase
end
end
end
def test_setup_hooks
call_order = []
tc = Class.new(MiniTest::Unit::TestCase) do
define_method :setup do
super()
call_order << :method
end
define_method :test2 do
call_order << :test2
end
define_method :test1 do
call_order << :test1
end
end
tc.add_setup_hook lambda { call_order << :proc }
argument = nil
tc.add_setup_hook do |arg|
argument = arg
call_order << :block
end
@tu.run %w[--seed 42]
assert_kind_of tc, argument
expected = [:method, :proc, :block, :test1,
:method, :proc, :block, :test2]
assert_equal expected, call_order
end
def test_teardown_hooks
call_order = []
tc = Class.new(MiniTest::Unit::TestCase) do
define_method :teardown do
super()
call_order << :method
end
define_method :test2 do
call_order << :test2
end
define_method :test1 do
call_order << :test1
end
end
tc.add_teardown_hook lambda { call_order << :proc }
argument = nil
tc.add_teardown_hook do |arg|
argument = arg
call_order << :block
end
@tu.run %w[--seed 42]
assert_kind_of tc, argument
expected = [:test1, :block, :proc, :method,
:test2, :block, :proc, :method]
assert_equal expected, call_order
end
def test_setup_and_teardown_hooks_survive_inheritance
call_order = []
parent = Class.new(MiniTest::Unit::TestCase) do
define_method :setup do
super()
call_order << :setup_method
end
define_method :teardown do
super()
call_order << :teardown_method
end
define_method :test_something do
call_order << :test
end
end
parent.add_setup_hook { call_order << :setup_hook }
parent.add_teardown_hook { call_order << :teardown_hook }
_ = Class.new parent
parent.add_setup_hook { call_order << :setup_after }
parent.add_teardown_hook { call_order << :teardown_after }
@tu.run %w[--seed 42]
# Once for the parent class, once for the child
expected = [:setup_method, :setup_hook, :setup_after, :test,
:teardown_after, :teardown_hook, :teardown_method] * 2
assert_equal expected, call_order
end
def util_expand_bt bt
if RUBY_VERSION =~ /^1\.9/ then
bt.map { |f| (f =~ /^\./) ? File.expand_path(f) : f }
@ -1084,6 +1228,11 @@ FILE:LINE:in `test_assert_raises_triggered_subclass'
@tc.pass
end
def test_prints
printer = Class.new { extend MiniTest::Assertions }
@tc.assert_equal '"test"', printer.mu_pp(ImmutableString.new 'test')
end
def test_refute
@assertion_count = 2