为什么在测试过程中构建的对象在测试过程中消失了(with RSPEC / Rails 5.2)?

Why does the object built during the test disappear during the test (with RSPEC / Rails 5.2)?

我正在测试 BusinessArea 视图在登录/未登录用户上下文中的可用性。 在测试开始时,我创建了业务区域对象 (test_ba) 感谢工厂,其中 returns 对象。

我'puts'test_ba.id看到它创建了。

然后我请求测试视图。

require 'rails_helper'

RSpec.describe BusinessArea, type: :request do
  include Warden::Test::Helpers

  describe "Business Areas pages: " do
    test_ba = FactoryBot.create(:business_area)
    puts test_ba.id
    context "when not signed in " do
      it "should propose to log in when requesting index" do
        get business_areas_path
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
     it "should propose to log in when requesting show" do
        puts test_ba.id
        get business_area_path(test_ba)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
    end
    context "when signed in" do
      before do
        get "/users/sign_in"
        test_user = FactoryBot.create(:user)
        login_as test_user, scope: :user
      end
      it "should display index" do
        get business_areas_path
        expect(response).to render_template(:index)
      end
      it "should display business area" do
        puts test_ba.id
        get business_area_path(test_ba)
        expect(response).to render_template(:show)
      end
    end
  end
end

测试似乎 运行 正确,但由于缺少记录,最后一步失败了!?!输出 returns:

>rspec spec/requests/business_areas_spec.rb
67
.67
..67
F

Failures:

  1) BusinessArea Business Areas pages:  when signed in should display business area
     Failure/Error: @business_area = BusinessArea.find(params[:id])

     ActiveRecord::RecordNotFound:
       Couldn't find BusinessArea with 'id'=67 
     # ./app/controllers/business_areas_controller.rb:159:in `set_business_area'
     # ./spec/requests/business_areas_spec.rb:35:in `block (4 levels) in <top (required)>'

Finished in 2.07 seconds (files took 13.05 seconds to load)
4 examples, 1 failure

Failed examples:

rspec ./spec/requests/business_areas_spec.rb:33 # BusinessArea Business Areas pages:  when signed in should display business area

你能帮我找出问题所在吗?

RSpec 有 letlet! 方法创建记忆化的助手,你应该使用它来设置你的测试依赖。 let 是延迟加载(块在您引用它之前不会被评估)而 let! 不是。

require 'rails_helper'

RSpec.describe BusinessArea, type: :request do
  include Warden::Test::Helpers

  describe "Business Areas pages: " do
    let!(:test_ba){  FactoryBot.create(:business_area) }

    context "when not signed in " do
      it "should propose to log in when requesting index" do
        get business_areas_path
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
     it "should propose to log in when requesting show" do
        puts test_ba.id
        get business_area_path(test_ba)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
    end
    context "when signed in" do
      before do
        get "/users/sign_in"
        test_user = FactoryBot.create(:user)
        login_as test_user, scope: :user
      end
      it "should display index" do
        get business_areas_path
        expect(response).to render_template(:index)
      end
      it "should display business area" do
        puts test_ba.id
        get business_area_path(test_ba)
        expect(response).to render_template(:show)
      end
    end
  end
end

But wah! Why doesn't my code work?

在 RSpec(以及任何好的测试框架)中,每个示例 运行 都是孤立的,并且有自己的设置和拆卸。这包括回滚数据库或清除它。 RSpec 甚至 运行 测试都没有按照设计的连续顺序进行。

您在外部上下文中定义的记录不会为每个测试创建 运行。在数据库回滚时的第一个示例之后它消失了。

如果您想为每个测试设置一些东西,请使用 before:

require 'rails_helper'

RSpec.describe BusinessArea, type: :request do
  include Warden::Test::Helpers

  describe "Business Areas pages: " do
    before do
      @test_ba = FactoryBot.create(:user)
    end

    context "when not signed in " do
      it "should propose to log in when requesting index" do
        get business_areas_path
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
     it "should propose to log in when requesting show" do
        puts @test_ba.id
        get business_area_path(test_ba)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
    end
    context "when signed in" do
      before do
        get "/users/sign_in"
        @test_user = FactoryBot.create(:user)
        login_as test_user, scope: :user
      end
      it "should display index" do
        get business_areas_path
        expect(response).to render_template(:index)
      end
      it "should display business area" do
        puts @test_ba.id
        get business_area_path(test_ba)
        expect(response).to render_template(:show)
      end
    end
  end
end

但是 let / let! 更适合设置简单的依赖关系。