【问题标题】:RSpec tests pass in isolation, but fail when run togetherRSpec 测试单独通过,但一起运行时失败
【发布时间】:2017-10-21 06:40:53
【问题描述】:

在我的code_controller_spec.rb 中,当我在code_controller_spec.rb 中运行测试时,我的测试通过了。但是,当我运行该套件时,只有 createeditupdate 测试在 code_controller_spec.rb 内失败。我真的不知道从哪里开始,我真的不知道为什么我的测试在一起运行时会失败。我有config.use_transactional_fixtures = false 并且正在使用database_cleaner。我的应用程序可以通过以下操作在本地正常运行,并且在创建或更新帖子时我没有收到任何错误。如果您需要更多信息,请告诉我。

当我运行该套件时,我遇到的失败是:

1) CodesController admin pages #create posts a new code post
     Failure/Error:
       post :create, params: {
         code: { 
           created_at: Date.today, 
           title: "Code things", 
           content: "The content of the code post",
           user_id: user.id
         }
       }

     ActionController::UrlGenerationError:
       No route matches {:action=>"create", :code=>{:created_at=>Fri, 20 Oct 2017, :title=>"Code things", :content=>"The content of the code post", :user_id=>1}, :controller=>"codes"}

2)  CodesController admin pages #edit edits a code post
     Failure/Error: get :edit, params: { id: code }

     ActionController::UrlGenerationError:
       No route matches {:action=>"edit", :controller=>"codes", :id=>#<Code id: 1, title: "Code post title", content: "Coding speak that not everyone can understand...", created_at: "2017-10-20 00:00:00", updated_at: "2017-10-21 06:05:27", user_id: 2>}

3) CodesController admin pages #update updates a code post
     Failure/Error: put :update, params: { id: code, code: code2 }

     ActionController::UrlGenerationError:
       No route matches {:action=>"update", :code=>{:title=>"Updated title", :content=>"Updated content"}, :controller=>"codes", :id=>#<Code id: 1, title: "Code post title", content: "Coding speak that not everyone can understand...", created_at: "2017-10-20 00:00:00", updated_at: "2017-10-21 06:05:27", user_id: 2>}

我的spec/controllers/user/codes_controller_spec.rb

RSpec.describe User::CodesController, type: :controller do

  let!(:user) { User.create(email: "user@example.com", password: "password") }
  let!(:code) { FactoryGirl.create(:code) }

  before do
    sign_in_as user
    expect(response).to have_http_status(:success)
  end

  describe "admin pages" do
    render_views

    context "#create" do
      it "posts a new code post" do
        post :create, params: {
          code: { 
            created_at: Date.today, 
            title: "Code things", 
            content: "The content of the code post",
            user_id: user.id
          }
        }
        expect(response).to redirect_to user_codes_path
        expect(flash[:success]).to eq "Post created successfully."
      end
    end

    context "#edit" do
      it "edits a code post" do
        get :edit, params: { id: code }
        expect(response).to render_template :edit
      end
    end

    context "#update" do
      let(:code2) do 
        { title: "Updated title", content: "Updated content" }
      end
      it "updates a code post" do
        put :update, params: { id: code, code: code2 }
        code.reload
        expect(response).to redirect_to user_code_path(code)
        expect(code.title).to eq code2[:title]
        expect(code.content).to eq code2[:content]
        expect(flash[:success]).to eq "Post updated successfully."
      end
    end
  end
end

我的spec/factories/post_factories.rb

FactoryGirl.define do
  factory :code do
    created_at Date.today
    title "Code post title"
    content "Coding speak that not everyone can understand..."

    association :user, factory: :user
  end

  factory :life do
    created_at Date.today
    title "Life post title"
    content "The world moves in mysterious ways; whether we want it to..."

    association :user, factory: :user
  end
end

我运行rspec --seed 123 --bisect,然后运行它的输出,但我的所有测试都通过了。我应该提到我对--bisect 很陌生。

这是rspec --seed 123 --bisect 输出,当我运行它时,我的所有测试都通过了。

rspec ./spec/controllers/user/codes_controller_spec.rb[1:1:1:1,1:1:2:1,1:1:3:1,1:1:4:1,1:1:5:1] ./spec/controllers/user/lives_controller_spec.rb[1:1:1,1:1:2] ./spec/features/admin_create_posts_spec.rb[1:1,1:2,1:3,1:4] ./spec/features/admin_edit_post_spec.rb[1:1,1:2,1:3] ./spec/features/clearance/user_signs_out_spec.rb[1:1] ./spec/features/clearance/visitor_resets_password_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6] ./spec/features/clearance/visitor_signs_in_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6,1:7,1:8] ./spec/features/clearance/visitor_signs_up_spec.rb[1:1,1:2,1:3,1:4,1:5,1:6,1:7,1:8] ./spec/features/clearance/visitor_updates_password_spec.rb[1:1,1:2,1:3] ./spec/features/homepage_spec.rb[1:1,1:2] ./spec/features/login_users_spec.rb[1:1,1:2] ./spec/features/logout_user_spec.rb[1:1] ./spec/features/showing_all_posts_spec.rb[1:1,1:2] ./spec/helpers/codes_helper_spec.rb[1:1] ./spec/helpers/lives_helper_spec.rb[1:1] ./spec/helpers/user/codes_helper_spec.rb[1:1] ./spec/helpers/user/lives_helper_spec.rb[1:1] ./spec/helpers/users_helper_spec.rb[1:1] ./spec/helpers/welcome_helper_spec.rb[1:1] ./spec/models/code_spec.rb[1:1] ./spec/models/life_spec.rb[1:1]

rails_helper.rb 中的我的 database_cleaner 配置

require database_cleaner

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  # config.fixture_path = "#{::Rails.root}/spec/fixtures"

  config.before(:all) do
    FactoryGirl.reload
  end

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb (or set it to false) to prevent uncommitted transactions being used in JavaScript-dependent specs.
                During testing, the app-under-test that the browser driver connects to uses a different database connection to the database connection used by the spec. The app's database connection would not be able to access uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    DatabaseCleaner.clean_with(:truncation)
  end  

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, type: :feature) do
    # :rack_test driver's Rack app under test shares database connection
    # with the specs, so continue to use transaction strategy for speed.
    driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

    if !driver_shares_db_connection_with_specs
      # Driver is probably for an external browser with an app under test that does *not*
      # share a database connection with the specs, so use truncation strategy.
      DatabaseCleaner.strategy = :truncation
    end
  end

  # adds this from
  # https://stackoverflow.com/questions/37753251/actionmailer-not-delivering-confirmation-emails-in-test-environment-rails-4
  config.before(:each, truncation: true) do 
    Database::Cleaner.strategy = :truncation 
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.append_after(:each) do
    DatabaseCleaner.clean
  end
end

已更新 rails routes 的输出

Prefix Verb   URI Pattern                             Controller#Action
              root GET    /                                       welcome#index
         passwords POST   /passwords(.:format)                    clearance/passwords#create
      new_password GET    /passwords/new(.:format)                clearance/passwords#new
           session POST   /session(.:format)                      clearance/sessions#create
edit_user_password GET    /users/:user_id/password/edit(.:format) clearance/passwords#edit
     user_password PATCH  /users/:user_id/password(.:format)      clearance/passwords#update
                   PUT    /users/:user_id/password(.:format)      clearance/passwords#update
                   POST   /users/:user_id/password(.:format)      clearance/passwords#create
             users POST   /users(.:format)                        clearance/users#create
           sign_in GET    /sign_in(.:format)                      clearance/sessions#new
          sign_out DELETE /sign_out(.:format)                     clearance/sessions#destroy
                   GET    /sign_out(.:format)                     clearance/sessions#destroy
           sign_up GET    /sign_up(.:format)                      clearance/users#new
        user_lives GET    /user/lives(.:format)                   user/lives#index
                   POST   /user/lives(.:format)                   user/lives#create
     new_user_life GET    /user/lives/new(.:format)               user/lives#new
    edit_user_life GET    /user/lives/:id/edit(.:format)          user/lives#edit
         user_life GET    /user/lives/:id(.:format)               user/lives#show
                   PATCH  /user/lives/:id(.:format)               user/lives#update
                   PUT    /user/lives/:id(.:format)               user/lives#update
                   DELETE /user/lives/:id(.:format)               user/lives#destroy
        user_codes GET    /user/codes(.:format)                   user/codes#index
                   POST   /user/codes(.:format)                   user/codes#create
     new_user_code GET    /user/codes/new(.:format)               user/codes#new
    edit_user_code GET    /user/codes/:id/edit(.:format)          user/codes#edit
         user_code GET    /user/codes/:id(.:format)               user/codes#show
                   PATCH  /user/codes/:id(.:format)               user/codes#update
                   PUT    /user/codes/:id(.:format)               user/codes#update
                   DELETE /user/codes/:id(.:format)               user/codes#destroy
             lives GET    /lives(.:format)                        lives#index
              life GET    /lives/:id(.:format)                    lives#show
             codes GET    /codes(.:format)                        codes#index
              code GET    /codes/:id(.:format)                    codes#show

【问题讨论】:

  • 你运行的是什么版本的 Rails?
  • @ThomasWalpole Rails 5
  • @ThomasWalpole 特别是 5.1.4
  • Rails 5.1+ 在测试环境中内置了 DB 连接共享,因此在大多数情况下不需要 database_cleaner。设置 config.use_transactional_fixtures = true 并删除 database_cleaner 看看是否有区别。如果它不能解决问题,请发布您的 database_cleaner 配置。
  • @ThomasWalpole 我按照你的建议做了,但同样失败了。我完全删除了database_cleaner 的配置并设置了config.use_transactional_fixtures = true。更新了上面的问题。

标签: ruby-on-rails rspec capybara rspec-rails


【解决方案1】:

我相信这是一个自动加载问题。如果您的::CodesControllerUsers::CodesController 之前加载,那么您的Users::CodesController 规范实际上是在使用::CodesController,因此无法创建正确的路由。单独运行时,会自动加载正确的类,并且一切正常。要解决此问题,需要在规范开头使用正确的类。

# spec/controllers/user/codes_controller_spec.rb

require 'user/codes_controller'
...

# spec/controllers/codes_controller_spec.rb

require 'codes_controller'
...

【讨论】:

  • 做到了!非常感谢您的时间和帮助。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
相关资源
最近更新 更多