在TDD期间,我应该为自定义验证创建测试吗?或者我应该测试整个对象的有效性?

时间:2012-02-02 07:47:00

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

我对TDD和单元测试非常陌生,而且我对自定义模型验证测试中应该采取的正确方法有很多疑问。

假设我有自定义验证:

User < ActiveRecord::Base
  validate :weird_validation

  def weird_validation
    # Validate the weird attribute
  end
end

我应该采用这种方法:

context "validation"
  it "pass the validation with weird stuff" do
    user = User.new weird: "something weird"
    user.should be_valid
  end


  it "should't pass the validation with normal stuff" do
    user = User.new weird: "something"
    user.should_not be_valid
    user.errors[:weird].size.should eq 1
  end
end

或者这个:

context "#weird_validation" do
  it "should not add an error if weird is weird" do
    user = User.new
    user.stub(:weird){"something weird"}
    user.errors.should_not_receive :add
    user.weird_validation.should eq true
  end

  it "should add an error if weird is not weird" do
    user = User.new
    user.stub(:weird){"something"}
    user.errors.should_receive(:add).with(:weird, anything())
    user.weird_validation.should eq false
  end
end

所以恕我直言

第一种方法

赞成

  • 测试行为
  • 轻松重构

缺点

  • 可靠的其他方法
  • 无关的东西会导致测试失败

第二种方法

赞成

  • 它不会传递任何其他东西,因为其他一切都是存根的
  • 这是代码应该做的所有事情的具体内容

缺点

  • 这是代码应该做的所有事情的具体内容
  • 重构验证可能会破坏测试

我个人认为正确的方法应该是第一种方法,但我无法避免认为我在其他方法中依赖太多而不是我想要测试的方法,如果测试失败则可能是因为有任何方法与模型。例如,它不会验证其他属性的验证是否失败。

使用第二种方法我实际上两次编写代码,这似乎是浪费时间和精力。但我正在对孤立的方法进行单元测试,以确定它应该做什么。 (而且我个人对每一种方法都这样做,我认为这非常糟糕且耗时)

在使用存根和模拟方面有中途吗?因为我采取了第二种方法,我认为我正在滥用它。

1 个答案:

答案 0 :(得分:0)

IMO第二种方法是最好的方法,因为您一次测试一个模型属性和验证(“单位”部分)。

为避免开销,您可以考虑使用shoulda。它对模型单元测试非常有效。我们通常使用factory_girl / mocha / shoulda组合进行功能测试(factory_girl和mocha对测试查询和命名范围也非常有帮助)。测试易于编写,阅读和维护:

# class UserTest < ActiveSupport::TestCase
# or
# describe 'User' do

  should have_db_column(:weird).of_type(:string).with_options(:limit=>255)
  should allow_value("something weird").for(:weird)
  should_not allow_value("something").for(:weird)
  should ensure_length_of(:weird).is_at_least(1).is_at_most(255)

# end

应该生成正/负匹配器,因此避免了大量的代码重复。