0

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

还是我应该简单地指望无论如何都不应该有这样的任务(因为一个干净的测试数据库不会有一个)?感谢您的意见。

更新(解决方案)

经过一番研究,我找到了changeRSpec 的匹配器:

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
4

2 回答 2

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

或者,如果您尝试测试缺少记录时应用程序的行为,请继续记忆变量或在 before 块中创建记录,但在特定测试中明确删除记录。

多个上下文

最后,如果您发现在单个测试中设置的状态太多,这通常是您应该考虑将测试拆分到不同上下文中的线索。例如,您可能希望将测试分成一个上下文,该上下文在记录不存在时检查行为,而另一个上下文则用于记录确实存在时的行为。

就像所有测试一样,它是一门艺术而不是一门科学。你的旅费可能会改变。

于 2012-07-15T17:20:44.630 回答
0

RSpec 2.11允许您将块传递给change,并且它期望块的返回值是改变的东西。我希望这对你有用:

expect { position }.to change { Task.where(:name => 'Read some books').count }.from(0).to(1)
于 2012-07-15T17:19:09.357 回答