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

发布于 2025-01-02 07:18:36 字数 1664 浏览 3 评论 0原文

我对 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

所以恕我直言

第一种方法

优点

  • 它测试行为
  • 容易重构

缺点

  • 依赖其他方法
  • 一些不相关的东西可能会使测试失败

第二种方法

优点

  • 它不依赖其他任何东西,因为其他所有东西都被存根
  • 它是代码应该做的所有事情的非常具体的

缺点

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

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

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

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

I'm very new on TDD and unit-testing, and I'm having quite a lot of doubts about the correct approach I should take during the tests of the custom model validations.

Suppose I have a custom validation:

User < ActiveRecord::Base
  validate :weird_validation

  def weird_validation
    # Validate the weird attribute
  end
end

Should I take this approach:

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

Or this one:

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

So IMHO

The first approach

Pros

  • It test behaviour
  • Easy refactoring

Cons

  • Dependable of other methods
  • Something unrelated could make the test fail

The second approach

Pros

  • It doesn't relay on anything else, since everything else is stubbed
  • It's very specific of all the things the code should do

Cons

  • It's very specific of all the things the code should do
  • Refactoring the validations could potentially break the test

I personally think the correct approach should be the first one, but I can't avoid to think that I'm relying too much in other methods rather than the one I want to test, and if the test fails it may be because of any method withing the model. For example, it would not validate if the validation of other attribute failed.

Using the second approach I'm practically writing the code twice, which seems like a waste of time and effort. But I'm unit-testing the isolated method about what it should do. (and I'm personally doing this for every single method, which is very bad and time consuming I think)

Is there any midway when it comes to using stubs and mocks? Because I've taken the second approach and I think I'm abusing it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人心善变 2025-01-09 07:18:36

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

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

IMO the second approach is the best one because you test your model properties and validations one at a time (the "unit" part).

To avoid overhead, you may consider using shoulda. It is really efficient for models unit testing. We're usually using a factory_girl/mocha/shoulda combination for functional testing (factory_girl and mocha are also very helpful to test queries and named scopes). Tests are easy to write, read and maintain :

# 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

Shoulda generates positive/negative matchers therefore avoids a lot of code duplication.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文