I have the following to remove the spaces on a specific attribute.
#before_validation :strip_whitespace
protected
def strip_whitespace
self.title = self.title.strip
end
And I want to test it. For now, I've tried:
it "shouldn't create a new part with title beggining with space" do
@part = Part.new(@attr.merge(:title => " Test"))
@part.title.should.eql?("Test")
end
What am I missing?
Validations won't run until the object is saved, or you invoke valid?
manually. Your before_validation
callback isn't being run in your current example because your validations are never checked. In your test I would suggest that you run @part.valid?
before checking that the title is changed to what you expect it to be.
app/models/part.rb
class Part < ActiveRecord::Base
before_validation :strip_whitespace
protected
def strip_whitespace
self.title = self.title.strip
end
end
spec/models/part_spec.rb
require 'spec_helper'
describe Part do
it "should remove extra space when validated" do
part = Part.new(:title => " Test")
part.valid?
part.title.should == "Test"
end
end
This will pass when the validation is included, and fails when the validation is commented out.
referring to @danivovich example
class Part < ActiveRecord::Base
before_validation :strip_whitespace
protected
def strip_whitespace
self.title = self.title.strip
end
end
the proper way to write the spec is to separately write spec on strip_whitespace method and then just check if model class have callback set on it, like this:.
describe Part do
let(:record){ described_class.new }
it{ described_class._validation_callbacks.select{|cb| cb.kind.eql?(:before)}.collect(&:filter).should include(:strip_whitespace) }
#private methods
describe :strip_whitespace do
subject{ record.send(:strip_whitespace)} # I'm using send() because calling private method
before{ record.stub(:title).and_return(' foo ')
it "should strip white spaces" do
subject.should eq 'foo'
# or even shorter
should eq 'foo'
end
end
end
if you need to skip callback behavior in some scenarios use
before{ Part.skip_callback(:validation, :before, :strip_whitespace)}
before{ Part.set_callback( :validation, :before, :strip_whitespace)}
Update 20.01.2013
BTW I wrote a gem with RSpec matchers to test this https://github.com/equivalent/shoulda-matchers-callbacks
In general I don't recommend callback at all. They are fine for example in this question, however once you do more complicated stuff like:
After create->
- link account to user
- create notification
- send email to Admin
...then you should create custom service object to deal with this and test them separately.
来源:https://stackoverflow.com/questions/7361036/rspec2-testing-a-before-validation-method