Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple RSpec
#!/usr/bin/env ruby
#encoding: UTF-8
################################################################################
################################################################################
################################################################################
# Overly simplistic implementation of how a RSpec test works #
################################################################################
def describe(object_under_test, &block)
@obj_under_test = object_under_test
@test_group = block
end
def subject
if @obj_under_test.is_a? Class
@subject ||= @obj_under_test.new
else
@obj_under_test
end
end
def before(&block) @before_hooks << block end
def after(&block) @after_hooks << block end
def it(description = nil, &block)
@examples << Example.new(description, block)
end
Example = Struct.new(:description, :test) do
attr_accessor :result
def call
@result = if test
begin
test.call
:passed
rescue => e
@failure = e
:failed
end
else
:pending
end
end
end
# Setup some variables to keep track of hooks
@before_hooks = []
@after_hooks = []
@examples = []
# Allow a very simply TestUnit style assert for ease of testing
def assert(truthy)
truthy or raise Error.new("Test failed.")
end
################################################################################
################################################################################
################################################################################
# A simplistic view of how tests are run #
################################################################################
def run
raise 'No object under test defined.' unless @obj_under_test
puts @obj_under_test
return unless @test_group
# Find out what tests need to be run
@test_group.call
# Run the tests
@examples.each_with_index do |example, index|
@subject = nil
puts "\n\nEXAMPLE #{index+1}:"
begin
@before_hooks.each(&:call)
example.call
puts "\n #{example.description} => #{example.result.upcase}\n"
rescue => e
puts "\n #{example.description} => failed\n"
ensure
@after_hooks.reverse_each(&:call)
end
end
end
################################################################################
################################################################################
################################################################################
# Here's our sample RSpec example #
################################################################################
class Thing
attr_reader :my_value
def initialize
@my_value = rand 5
end
end
describe Thing do
before { puts "BEFORE_BLOCK:: First before block" }
after do
print "AFTER_BLOCK:: should be called last!"
print " Reset @tmp_value(#{@tmp_value.inspect}) => "
@tmp_value = nil
puts "@tmp_value(#{@tmp_value.inspect})"
end
it 'has access to subject' do
p subject
assert subject.my_value < 5
end
it 'subject changes only between tests' do
p subject
assert subject.equal?(subject)
end
it "fails on error" do
raise Error.new 'Sad face'
end
it 'works!' do
assert @tmp_value == 'test'
end
before do
@tmp_value = 'test'
print "BEFORE_BLOCK:: Another before block"
puts " Set @tmp_value(#{@tmp_value.inspect})"
end
it 'is pending'
after { puts "AFTER_BLOCK:: should be called first!!" }
end
################################################################################
################################################################################
# Now we run the example
run
# Output of the tests
Thing
EXAMPLE 1:
BEFORE_BLOCK:: First before block
BEFORE_BLOCK:: Another before block Set @tmp_value("test")
#<Thing:0x007fcd110a26a8 @my_value=3>
has access to subject => PASSED
AFTER_BLOCK:: should be called first!!
AFTER_BLOCK:: should be called last! Reset @tmp_value("test") => @tmp_value(nil)
EXAMPLE 2:
BEFORE_BLOCK:: First before block
BEFORE_BLOCK:: Another before block Set @tmp_value("test")
#<Thing:0x007fcd110a2220 @my_value=4>
subject changes only between tests => PASSED
AFTER_BLOCK:: should be called first!!
AFTER_BLOCK:: should be called last! Reset @tmp_value("test") => @tmp_value(nil)
EXAMPLE 3:
BEFORE_BLOCK:: First before block
BEFORE_BLOCK:: Another before block Set @tmp_value("test")
fails on error => FAILED
AFTER_BLOCK:: should be called first!!
AFTER_BLOCK:: should be called last! Reset @tmp_value("test") => @tmp_value(nil)
EXAMPLE 4:
BEFORE_BLOCK:: First before block
BEFORE_BLOCK:: Another before block Set @tmp_value("test")
works! => PASSED
AFTER_BLOCK:: should be called first!!
AFTER_BLOCK:: should be called last! Reset @tmp_value("test") => @tmp_value(nil)
EXAMPLE 5:
BEFORE_BLOCK:: First before block
BEFORE_BLOCK:: Another before block Set @tmp_value("test")
is pending => PENDING
AFTER_BLOCK:: should be called first!!
AFTER_BLOCK:: should be called last! Reset @tmp_value("test") => @tmp_value(nil)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.