Hi gang.
I’ve come across what I believe to be unexpected behavior for some of my
before :each blocks, and I wonder if anyone can enlighten me as to why
this
is happening.
The surprising thing happens when I run a ‘before :each’ inside of an
each
block on a Hash. I have a #before_save hook in my ActiveRecord model.
When I
call @sample_model.save from the before block, the model runs a
uniqueness
validation. However, when I save from within the example, the save works
fine.
Below is the minimal test case I was able to put together:
class SampleClassMigration < ActiveRecord::Migration
def self.up
create_table :sample_classes do |t|
t.string :sample_field
t.string :attrib_1
t.string :attrib_2
end
end
end
class SampleClass < ActiveRecord::Base
validates_uniqueness_of :sample_field
before_save :prep
def prep
self.sample_field = ‘sample_value’
end
end
describe SampleClass do
EXAMPLES = {
:attrib_1 => ‘foo’,
:attrib_2 => ‘bar’
}
EXAMPLES.each do |key, value|
before(:each) do
@sample = SampleClass.new(key => value)
#In the passing case, this call to #save
#is moved into the ‘it’ block
@sample.save
end
it "key : #{value}\tvalue : #{key.to_s}" do
#in the other case, I call the spec here
@sample.should be_valid
end
end
end
It was my expectation that calling an instance method in the before
block
would be the same as calling it within the example block. Instead, I get
two
different results. When called from within the it block, both examples
pass.
When called from within the before block, they both fail:
‘SampleClass key : bar value : attrib_2’ FAILED
Expected #<SampleClass id: 2, sample_field: “sample_value”, attrib_1:
“foo”,
attrib_2: nil> to be valid, but it was not
Errors: Sample field has already been taken
./spec/models/minimal_spec.rb:20:
‘SampleClass key : foo value : attrib_1’ FAILED
Expected #<SampleClass id: 2, sample_field: “sample_value”, attrib_1:
“foo”,
attrib_2: nil> to be valid, but it was not
Errors: Sample field has already been taken
./spec/models/minimal_spec.rb:20:
I’m surprised to see that the example fails, but I’m more surprised to
see
that it fails both times. It is apparently the case that the “before”
block
is executed on every iteration of the “each” block (but that the
examples
themselves are executed later).
- Is this a bug?
- Is it a known behavior?
- Is there a “BDD-theoretical” better way to do something like this
(assuming a larger hash of examples, for instance)?
I’m using:
gem ‘rails’, ‘2.3.5’
gem ‘mysql’
group :development, :test do
gem ‘database_cleaner’
gem ‘rspec-rails’, ‘1.3.2’
gem ‘rspec’, ‘1.3.0’
end
DatabaseCleaner is properly configured, and runs for many other specs.
(Indeed, it even runs correctly between steps, as demonstrated by the
case
where the specs pass).
Thanks,
Andrew Kasper