【问题标题】:How can I keep the database populated between contexts in rspec?如何在 rspec 的上下文之间填充数据库?
【发布时间】:2017-06-21 23:47:16
【问题描述】:

我刚刚开始使用 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 清空它?

【问题讨论】:

    标签: ruby-on-rails rspec


    【解决方案1】:

    是的,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
    

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

    【讨论】:

      【解决方案2】:

      如果您想测试您的控制器,最好编写彼此独立的 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

      【讨论】:

        猜你喜欢
        • 2011-03-31
        • 1970-01-01
        • 2020-04-12
        • 2023-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-18
        • 1970-01-01
        相关资源
        最近更新 更多