My Rails模型:任务has_many位置。
场景:当我创建一个新位置时,它应该创建一个任务。我想测试一下,我这样做:
context "creating a new position" do
let(:position) { create :position, name: 'Read some books', :task => nil }
it "should create a simple task" do
Task.find_by_name('Read some books').should be_nil # First should
position # Execute let() block (FactoryGirl is lazy evaluating)
Task.find_by_name('Read some books').should_not be_nil # Second (more relevant) should
end
end
那么我应该如何改进我的考试呢?第一个“应该”只是确保没有任务,所以我们可以确保创建位置创建任务。但这违反了“只有一个应该阻止”的原则。那么这个怎么样?
context "creating a new position" do
let(:position) do
position = create :position, name: 'Read some books', :task => nil
Task.delete_all
position
end
it "should create a simple task" do
position # Execute let() block (FactoryGirl is lazy evaluating)
Task.find_by_name('Read some books').should_not be_nil
end
end
或者我应该依靠这样一个事实,即不应该有这样的任务(因为一个干净的测试数据库不会有一个)?感谢您的意见。
更新(解决方案)
经过一些研究后,我找到了RSpec的change
匹配器:
let(:position) { create :position, name: 'Read some books', :task => nil }
it "should create a simple task" do
# Thanks to FactoryGirl's lazy evaluation of let(), the position doesn't yet exist in the first place, and then after calling position in the expect{} block, it is created.
expect { position }.to change{ Task.count(conditions: { name: 'Read some books' }) }.by(1)
end
答案 0 :(得分:1)
我不会详细说明测试本身是否对任何程度都有用。对我来说,他们似乎在运用基本的数据库功能而不是应用程序逻辑,这是一种边际效用,但只有你才能真正决定测试的重要性。
在你给出的例子中,没有真正的理由使用let块来记忆变量。如果只有一个测试需要记录,则仅在该特定测试中实例化它。例如:
context 'creating a new position' do
it 'should be nil when the position record is missing' do
Task.find_by_name('Read some books').should be_nil
end
it 'should successfully create a position' do
create :position, name: 'Read some books', :task => nil
Task.find_by_name('Read some books').should_not be_nil
end
end
或者,如果您尝试测试应用程序在缺少记录时的行为方式,那么请继续记住变量或在之前的块中创建记录,但明确删除该记录中的记录测试
最后,如果您发现在个别测试中设置的状态太多,那通常就是您应该考虑将测试分成不同的上下文的线索。例如,您可能希望将测试分成一个上下文,该上下文在记录不存在时检查行为,并且在记录 do 时存在单独的上下文。
就像所有测试一样,它不仅仅是一门科学而是艺术。您的里程可能会有所不同。
答案 1 :(得分:0)
RSpec 2.11允许您将块传递给change
,并且它期望块的返回值是变化的。我希望这对你有用:
expect { position }.to change { Task.where(:name => 'Read some books').count }.from(0).to(1)