Skip to content

Instantly share code, notes, and snippets.

@seangeo
Last active December 17, 2015 20:49
Show Gist options
  • Save seangeo/5670733 to your computer and use it in GitHub Desktop.
Save seangeo/5670733 to your computer and use it in GitHub Desktop.
Idempotent example groups that only run before(:each) once for their children.
class IdempotentExample < RSpec::Core::Example
# Copied from RSpec::Core::Example but modifed to run
# the block without running before and after :each.
#
# Definitely needs work.
#
def run(example_group_instance, reporter)
@example_group_instance = example_group_instance
@example_group_instance.example = self
begin
start(reporter)
begin
@example_group_instance.instance_eval(&@example_block)
rescue RSpec::Core::Pending::PendingDeclaredInExample => e
@pending_declared_in_example = e.message
rescue StandardError => e
set_exception(e)
end
finish(reporter)
rescue Exception => e
set_exception(e)
ensure
begin
assign_generated_description
rescue Exception => e
set_exception(e, "while assigning the example description")
end
end
end
end
module IdempotentExampleGroup
def it(desc = nil, *args, &block)
options = build_metadata_hash_from(args)
options.update(:pending => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
examples << IdempotentExample.new(self, desc, options, block)
examples.last
end
def run_examples(reporter)
instance = new
# Don't actually know what this does, but I need it
def instance.all_apply?(options)
true
end
set_ivars(instance, before_all_ivars)
# Around filters need some work
# with_around_each_hooks do
run_before_each_hooks(instance)
filtered_examples.ordered.map do |example|
next if RSpec.wants_to_quit
succeeded = example.run(instance, reporter)
RSpec.wants_to_quit = true if fail_fast? && !succeeded
succeeded
end.all?
# end
ensure
run_after_each_hooks(instance)
instance.instance_variables.each do |ivar|
instance.instance_variable_set(ivar, nil)
end
end
end
module Idempotent
def idempotent(*args, &example_group_block)
mygb = proc {
self.extend(IdempotentExampleGroup)
self.instance_eval(&example_group_block)
}
describe(*args, &mygb)
end
RSpec.configure { |c| c.extend self }
end
$counter = 0
$normal_counter = 0
describe 'Idempotent Example' do
idempotent do
let!(:counter) { $counter += 1 }
it { true.should be_true }
it { false.should be_false }
it { 1.should == 0 } # failure showing that we still run the other blocks
it { 1.should == 1 }
it { counter.should == 1 }
it { 1.should == 2 }
end
describe do
let!(:start) { $normal_counter += 1 }
it { true.should be_true }
it { false.should be_false }
it { start.should == 3 }
end
end
..F..F...
Failures:
1) Idempotent Example
Failure/Error: it { 1.should == 0 } # failure showing that we still run the other blocks
expected: 0
got: 1 (using ==)
# ./test.rb:106:in `block (3 levels) in <top (required)>'
# ./test.rb:30:in `instance_eval'
# ./test.rb:30:in `run'
# ./test.rb:71:in `block in run_examples'
# ./test.rb:69:in `map'
# ./test.rb:69:in `run_examples'
2) Idempotent Example
Failure/Error: it { 1.should == 2 }
expected: 2
got: 1 (using ==)
# ./test.rb:109:in `block (3 levels) in <top (required)>'
# ./test.rb:30:in `instance_eval'
# ./test.rb:30:in `run'
# ./test.rb:71:in `block in run_examples'
# ./test.rb:69:in `map'
# ./test.rb:69:in `run_examples'
Finished in 0.00254 seconds
9 examples, 2 failures
Failed examples:
rspec ./test.rb:54 # Idempotent Example
rspec ./test.rb:54 # Idempotent Example
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment