Introducing: MicroTest

Posted by Mathew Abonyi Wed, 10 Jan 2007 21:04:32 GMT

Something I cooked up in an hour for bootstrap testing a testing framework.

If anyone actually wants me to maintain it, just give a shout and I’ll gemify it.



# A super-small testing suite.
# Just two ways to assert:
#   expect { (whatever must return true) }
#   do_not_expect { (whatever must return false) }
#
# A microtest looks like this:
#
#   class BinaryMicroTest < MicroTest
#     def should_exit_cleanly
#       expect do
#         `ruby #{myexec}`
#         $? == 0
#       end
#     end
#   end
#
class MicroTest

  class MicroFailure < StandardError; end

  class << self

    attr_accessor :passed, :failed, :executed, :expectations, :planned, :plan, :failures

    def run
      init
      execute
      report
    end

    def init
      self.passed, self.failed, self.executed, self.expectations = 0, 0, 0, 0
      self.planned, self.plan = harvest
      self.failures = []
    end

    def harvest
      plan = []
      ObjectSpace.each_object(Class) do |k|
        if k.respond_to?(:superclass) && k.superclass == MicroTest
          plan << [k, k.instance_methods.grep(/^should_/)]
        end
      end
      planned = plan.inject(0) { |c, ary| c += ary[1].size; c }
      [planned, plan]
    end

    def execute
      puts "Running #{self.planned} test(s)..."
      self.plan.each do |klass, tests|
        tests.each do |test|
          instance = klass.new
          r = catch_failures(klass, test) { instance.send(test) }
          if r
            self.passed += 1
            print "."
            STDOUT.flush
          else
            self.failed += 1
            print "F"
            STDOUT.flush
          end
          self.expectations += instance.expectation_count
          self.executed += 1
        end
      end
    end

    def catch_failures(klass, test)
      begin
        yield
        true
      rescue Exception => e
        self.failures << [klass, test, e]
        false
      end
    end

    def report
      puts "\n\n"
      puts "%d planned, %d executed, %d passed, %d failed.\n%d expectations found." %
        [self.planned, self.executed, self.passed, self.failed, self.expectations]
      unless self.failures.empty?
        puts "\nFAILURE REPORT\n"
        self.failures.each { |f| report_failure(f) }
      end
    end

    def report_failure(f)
      puts "Suite: #{f[0]}\nTest: #{f[1]}\nException: #{f[2].class}\nMessage: #{f[2].message}"
      puts ("\t" << f[2].backtrace.join("\n\t"))
    end

  end

  attr_accessor :expectation_count

  def initialize
    self.expectation_count = 0
  end

  def expect(&block)
    self.expectation_count += 1
    raise MicroFailure, "should be true" unless block.call
  end

  def do_not_expect(&block)
    self.expectation_count += 1
    raise MicroFailure, "should be false" if block.call
  end

end

at_exit do
  MicroTest.run
end

Just dump that in a helper file and require it, as per normal Test::Unit practices.

Posted in ,  | 1 comment | 3 trackbacks

Comments

  1. robert said 5 months later:

    hi all.

Trackbacks

Use the following link to trackback from your own site:
http://www.mathewabonyi.com/articles/trackback/40

  1. From Animal.
    Free animal sex videos.
    Animal fuck. Animal sex free. Animal mating. Animal rights. Animal sex. Free animal sex pics.
  2. From Love ya dog super shape.
    Dog dogs canine wonderland i love dogs com.
    Personalized i love my dog stocking. Puppy love match com dating site for dog lovers. Love ya dog super shape. Dogster for the love of dog blog.
  3. From Underage porn mpeg.
    Underage asian hentai porn.
    Free illegal underage porn. Underage porn.

(leave url/email »)

   Comment Markup Help Preview comment