问题
I'm trying out the whole TDD and I'm running into a problems with validate presence. I have a model called Event and I want to ensure that when an Event is created that a title a price and a summary exists.
Unit Test Code
class EventTest < ActiveSupport::TestCase
test "should not save without a Title" do
event = Event.new
event.title = nil
assert !event.save, "Save the Event without title"
end
test "should not save without a Price" do
event = Event.new
event.price = nil
assert !event.save, "Saved the Event without a Price"
end
test "should not save without a Summary" do
event = Event.new
event.summary = nil
assert !event.save, "Saved the Event without a Summary"
end
end
I run the test I get 3 FAILS. Which is Good.
Now I want to to just get the title test to pass first with the following code in the Event model.
class Event < ActiveRecord::Base
validates :title, :presence => true
end
When I re-run the test I get 3 PASSES where I would think I should have gotten 1 PASS and 2 FAILS. Why am I getting 3 PASSES?
回答1:
I have two test helper methods that can make this sort of thing easier to diagnose:
def assert_created(model)
assert model, "Model was not defined"
assert_equal [ ], model.errors.full_messages
assert model.valid?, "Model failed to validate"
assert !model.new_record?, "Model is still a new record"
end
def assert_errors_on(model, *attrs)
found_attrs = [ ]
model.errors.each do |attr, error|
found_attrs << attr
end
assert_equal attrs.flatten.collect(&:to_s).sort, found_attrs.uniq.collect(&:to_s).sort
end
You'd use them in cases like this:
test "should save with a Title, Price or Summary" do
event = Event.create(
:title => 'Sample Title',
:price => 100,
:summary => 'Sample summary...'
)
assert_created event
end
test "should not save without a Title, Price or Summary" do
event = Event.create
assert_errors_on event, :title, :price, :summary
end
This should show if you're missing a validation that you expected and will also give you feedback on specific validations that have failed when not expected.
回答2:
When you created the model with Event.new, all attributes initially have a value of nil. This means that all 3 attributes you are checking are already nil (so event.title = nil and event.price = nil don't actually do anything). Since title has been marked for validation to ensure its presence, unless you set title to something other than nil, you will not be able to save the model.
Perhaps try adding this to your test class:
setup do
@event_attributes = {:title => "A title", :price => 3.99, :summary => "A summary"}
end
Then instead of:
event = Event.new
event.title = nil
Use:
event = Event.new(@event_attributes.merge(:title => nil))
Do the same for all your tests (substituting :title with whatever attribute you are validating presence for)
Also, there's no reason to call save to test for a valid state. You can just call event.valid? to avoid trips to the database where not needed.
来源:https://stackoverflow.com/questions/8993068/unit-testing-validates-presence-of-odd-behaviour