如何在rspec中的上下文之间保留数据库?

时间:2017-06-21 23:47:17

标签: ruby-on-rails rspec

我刚刚开始使用Rails,我正在为RSpec的Todo列表应用编写一些单元测试。我已经编写并运行了REST API,但现在我似乎无法找出测试的问题。这是规范:

require 'rails_helper'

describe "Lists API" do
  context "from start" do
    it 'is empty' do
      get "/lists"
      expect(response).to be_success
      expect(json.size).to eq(0) 
    end

    it 'can create Lists' do  
      post "/lists", :list => {:title => "First List", :status => "Unstarted"}
      expect(response).to be_success

      post "/lists", :list => {:title => "Second List", :status => "Unstarted"}
      expect(response).to be_success

      #lines only here to show the problem only exists in a different test block
      get "/lists"
      expect(response).to be_success
      expect(json.size).to eq(2) 
    end

  end

  context "once populated" do
    it 'can view created lists' do
      get "/lists"
      expect(response).to be_success
      expect(json.size).to eq(2)
    end
  end


end

然后当我运行RSpec时,我收到此错误:

Failures:

  1) Lists API once populated can view created lists
     Failure/Error: expect(json.size).to eq(2)

       expected: 2
            got: 0

       (compared using ==)

似乎数据库正在为每个it块清空。那是对的吗?有没有办法为每个describe创建一个新的数据库,但没有为每个it清空?

2 个答案:

答案 0 :(得分:0)

是的,rspec将独立处理每个示例(it块)。

您可能想要考虑的一件事是通过操作和端点分解您的规范,例如:

describe 'Lists API' do
  describe 'GET lists' do
    context 'when lists empty' do
      before(:each) do
        get '/lists'
      end

      it 'responds with success'
      it 'json response is empty'
    end

    context 'when lists present' do
      let!(:list) { List.create(title: 'First List', status: 'Unstarted') }

      before(:each) do
        get '/lists'
      end

      it 'responds with success'
      it 'json response is present'
    end
  end

  describe 'POST lists' do
    it 'can create lists'
  end
end

这样,您可以更好地隔离和组织您正在测试的内容。实际上,您要测试的是您可以成功创建列表并成功获取/呈现列表(包括空列表和列表项)。

答案 1 :(得分:0)

如果您想测试控制器,可以通过编写彼此独立的it块来获得更好的服务。

<强>为什么: 在块之间保存对象可以解决向/lists发布两次并使一个帖子失败的问题。在这种情况下,您的POST it块将失败并且您的GET it块将失败,因为GET依赖于POST成功。这很令人困惑,因为你的GET操作可能没有任何问题,但无论如何它的测试都会失败。

改进:为控制器中的每个操作设置隔离测试,例如:

describe 'GET /lists' do
  before do
    List.create(title: 'first list', status: 'Unstarted')
    List.create(title: 'second list', status: 'Unstarted')
  end

  it 'renders all lists' do
    get '/lists'

    expect(response).to be_success
    expect(json.length).to eq(2)
  end
end

(使用before创建两个提取的记录) 和

describe 'POST /lists' do
  it 'can create Lists' do  
    post "/lists", :list => {:title => "First List", :status => "Unstarted"}

    expect(response).to be_success
    expect(List.count).to eq(1)
  end
end

这样一来,如果GET或POST被破坏,你就会知道哪个是真正导致问题的。

最后,如果您仍想测试更实际的用户流,请考虑编写一个大型集成测试。这是the Rails docs integration infoRSpec's controller integration info