在 TDD 期间,我应该为自定义验证创建测试吗?或者我应该测试整个对象的有效性?
我对 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
IMO 第二种方法是最好的方法,因为您一次测试一个模型属性和验证(“单元”部分)。
为了避免开销,您可以考虑使用 shoulda。它对于模型单元测试非常有效。我们通常使用 factory_girl/mocha/shoulda 组合用于功能测试(factory_girl 和 mocha 对于测试查询和命名范围也非常有帮助)。测试易于编写、阅读和维护:
应该生成正/负匹配器,因此可以避免大量代码重复。
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 :
Shoulda generates positive/negative matchers therefore avoids a lot of code duplication.