Skip to content

Instantly share code, notes, and snippets.

@h0rs3r4dish
Created April 3, 2011 18:16
Show Gist options
  • Save h0rs3r4dish/900632 to your computer and use it in GitHub Desktop.
Save h0rs3r4dish/900632 to your computer and use it in GitHub Desktop.
This is my <100-line spec framework, and some accompanying demo code that showcases all the features.
#!/usr/bin/env ruby
module Spec
class AssertionError < Exception; end
class Should
def initialize(obj, invert=false)
@invert = invert
@self = obj
end
def ==(other)
test = (@self == other)
raise AssertionError unless (@invert ? !test : test)
end
def !=(other)
@invert = !@invert; self == other; @invert = !@invert
end
end
class MockObject
def initialize(vars)
@vars = vars
@calls = Hash.new
@accept_any_call = false
end
def method_missing(method, *a)
@calls[method] = true if @calls.key? method
return @vars[method] if @vars.key? method
return if @calls.key?(method) or @accept_any_call
raise "No method #{method}"
end
def should_receive(call)
@calls[call] = false
end
def received?
@calls.each_pair { |call,b| raise "Never got #{call}" if !b }
end
def as_null_object
@accept_any_call = true
self
end
end
class TestCase
attr_reader :subject
def initialize(const,block)
@const = const
@tests = @passed_tests = 0
@start_time = Time.now
@exceptions = Array.new
instance_eval &block
end
def it(desc)
@subject = @const.new if @const.class == Class
@mocks = Array.new
@tests += 1
begin
yield
@mocks.each { |m| m.received? }
print '.'
@passed_tests += 1
rescue Exception => e
print 'F'
@exceptions.push e
end
end
def mock(properties)
(@mocks.push Spec::MockObject.new(properties)).last
end
def test_info
{ :tests => @tests, :passed => @passed_tests,
:time => (Time.now - @start_time),
:exceptions => @exceptions }
end
end
end
def describe(const, &block)
info = Spec::TestCase.new(const, block).test_info
puts "\n\n%d/%d tests passed in %0.5f seconds" % info.values[0..2]
puts "Problems:\n" + info[:exceptions].map { |e|
"- "+e.message+e.backtrace[0..6].select { |b|
!(b =~ /spec/) }.map { |b| "\n"+(" "*4)+b }.join
}.join("\n") unless info[:exceptions].empty?
end
class Object
def should; Spec::Should.new(self); end
def should_not; Spec::Should.new(self, true); end
end
ARGV.each { |file| require_relative file }
class Walrus
def initialize
@full = false
end
def give_gift(obj)
if obj.edible then
@full = true
obj.digest!
else
obj.throw_away!
end
end
def full?
@full
end
end
describe Walrus do
it "starts its life hungry" do
subject.full?.should != true
end
it "eats food" do
milk = mock(:edible => true)
milk.should_receive :digest!
subject.give_gift(milk)
subject.full?.should == true
end
it "doesn't eat non-food" do
shoe = mock(:edible => false).as_null_object
subject.give_gift(shoe)
subject.full?.should_not == true
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment