单元测试验证奇怪行为的存在

时间:2012-01-24 19:45:10

标签: ruby-on-rails ruby unit-testing validation testing

我正在尝试整个TDD,我遇到了验证存在的问题。我有一个名为Event的模型,我想确保在创建Event一个title pricesummary时存在。

单元测试代码

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

我运行测试我 3 FAILS。哪个好。 现在我想让title测试首先通过Event模型中的以下代码传递。

class Event < ActiveRecord::Base

  validates :title, :presence => true

end

当我重新进行测试时,我得到 3 PASSES ,我认为我应该得到 1 PASS和2 FAILS 。我为什么要3次通过?

2 个答案:

答案 0 :(得分:2)

我有两个测试辅助方法可以使这类事情更易于诊断:

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

你会在这样的情况下使用它们:

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

如果您错过了预期的验证,这将显示,并且还会针对未预期的失败的特定验证提供反馈。

答案 1 :(得分:1)

使用Event.new创建模型时,所有属性的值最初都为nil。这意味着您检查的所有3个属性都已为零(因此event.title = nilevent.price = nil实际上没有做任何事情)。由于title已标记为进行验证以确保其存在,因此除非您将title设置为非零值,否则您将无法保存模型。

也许尝试将此添加到您的测试类中:

setup do
  @event_attributes = {:title => "A title", :price => 3.99, :summary => "A summary"}
end

然后代替:

event = Event.new
event.title = nil

使用:

event = Event.new(@event_attributes.merge(:title => nil))

对所有测试执行相同操作(用:title替换您正在验证存在的任何属性)

此外,没有理由要求save测试有效状态。您只需调用event.valid?即可避免在不需要的地方访问数据库。