RSpec:控制器测试应该如何?

时间:2014-04-07 23:55:36

标签: ruby-on-rails rspec

我正在研究控制器rspec,我开始讨厌RSpec,因为它与如何构建测试的不一致。应该有一种方法可以做一件事。我希望听到你说我做错了所以我可以学到它应该如何,但我读的越多,我就越混乱。

让我们忘记should,只关注新的expect语法并采用这个简单的支架:

describe "foo" do
  before do
    @foo = create(:foo)
    # _A_
  end
  # _B_
end

我在_A__B_标记了2个位置。比以delete动作为例。对于成功背景delete操作最常见的期望是:

  1. 从数据库中删除某些内容
  2. 重定向到某个页面
  3. 显示一些闪光[:notice]
  4. 因此,对第一期望的测试可以是:

    _B_: it { expect{delete :destroy, id @foo}.to change(Foo, :count).by(-1)
    

    但要测试第二个期望,将delete移到before部分会很好:

    _A_: delete :destroy, id: @foo
    _B_: it { expect(response).to redirect_to some_url }
    
    必须先运行

    delete才能使用expect(response)。 与第三名类似:

    _A_: delete :destroy, id: @foo
    _B_: it { expect(flash[:notice]).to_not be_nil }
         it { expect(flash[:error]).to be_nil }
    

    那么如何将1st和2nd和3rd放入一个看起来很清晰的describe区块?

2 个答案:

答案 0 :(得分:1)

describe "delete" do
  before(:each) do
    @foo = Foo.create
  end
  it "should delete from the database" do
    expect(delete :destroy, id: @foo).to change(Foo, :count).by(-1)
  end
  context do
    before(:each) do
      delete :destroy, id: @foo
    end
    it "should redirect" do
      expect(response).to redirect_to some_url
    end
    it "should set the flash" do
      expect(flash[:notice]).to_not be_nil
      expect(flash[:error]).to be_nil
    end
  end
end

是的,删除操作会出现两次。测试代码通常很难干。恕我直言,你不应该在编写规格时牺牲清晰度以节省空间。

  

应该有一种方法可以做一件事。

当然,我们可以采用最佳做法,但这并不意味着如果有其他令人信服的理由,所有规范都需要以相同的方式编写。

答案 1 :(得分:1)

你可以把它们放在三个不同的测试中:

describe "foo" do
  before(:each) do
    @foo = create(:foo)
  end

  it 'removes something from database' do
    expect{delete :destroy, id @foo}.to change(Foo, :count).by(-1)
  end

  it 'redirects to some page' do
    delete :destroy, id: @foo
    expect(response).to redirect_to some_url
  end

  it 'shows some flash[:notice]' do
     delete :destroy, id: @foo
     expect(flash[:notice]).to_not be_nil 
     expect(flash[:error]).to be_nil 
  end
end