从 rails 4 升级后 users_controller_test 出错

Error in users_controller_test after upgrading from rails 4

我 运行 通过 mhartls's rails 教程几次 rails 4.x 只是为了好玩,我又开始了,但更新到rails 5.0.0.beta1。 我设法找到了第 9 章之前所有不兼容问题的解决方案。具体来说,我无法对用户控制器上的销毁操作进行测试。我得到:

ERROR["test_should_redirect_destroy_when_not_logged_in", UsersControllerTest, 1.489256506320089]
 test_should_redirect_destroy_when_not_logged_in#UsersControllerTest (1.49s)
URI::InvalidURIError:         URI::InvalidURIError: bad URI(is not URI?): http://www.example.com:80destroy
            test/controllers/users_controller_test.rb:49:in `block (2 levels) in <class:UsersControllerTest>'
            test/controllers/users_controller_test.rb:48:in `block in <class:UsersControllerTest>'

URI::InvalidURIError: bad URI(is not URI?): http://www.example.com:80destroy
    test/controllers/users_controller_test.rb:49:in `block (2 levels) in <class:UsersControllerTest>'
    test/controllers/users_controller_test.rb:48:in `block in <class:UsersControllerTest>'

bin/rails test test/controllers/users_controller_test.rb:47

我的控制器销毁动作:

def destroy
  User.find(params[:id]).destroy
  flash[:success] = "User deleted"
  redirect_to users_url
end

我的测试:

test "should redirect destroy when logged in as a non-admin" do
  log_in_as(@other_user, integration_test: 'true')
  assert_no_difference 'User.count' do
    delete :destroy, params: { id: @user }
  end
  assert_redirected_to root_url
end

link 确实有效,但测试失败。我可以通过添加这样的路由来让测试通过:delete 'delete_user' => 'users#destroy' 并将测试更改为:delete delete_user_path params:{id: @user} 但是,实际站点和测试使用不同的路由,所以我不知道是否我可以相信这一点。如果我从用户 resources: resources :users, except: :destroy 中删除 destroy,那么页面 link 将不起作用,但测试仍然通过。我看不到如何在页面 link 上使用 delete_user 路由,并且似乎无法让 user#destroy 路由在测试中工作。我知道这不是集成测试,但此解决方法解决了其他几个问题。稍后我会重构,这样它就有意义了。

附加相关控制器代码:

before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user,   only: [:edit, :update]
before_action :admin_user,     only: :destroy

private

  def user_params
    params.require(:user).permit(:name, :email, :password,
                                 :password_confirmation)
  end

  # Before filters

  # Confirms a logged-in user.
  def logged_in_user
    unless logged_in?
      store_location
      flash[:danger] = "Please log in."
      redirect_to login_url
    end
  end

  # Confirms the correct user.
  def correct_user
    @user = User.find(params[:id])
    redirect_to(root_url) unless current_user?(@user)
  end

  # Confirms an admin user.
  def admin_user
    redirect_to(root_url) unless current_user.admin?
  end

Test Helper Code:

    # Logs in a test user. (I think all tests must be like integration)
def log_in_as(user, options = {})
  password    = options[:password]    || 'password'
  remember_me = options[:remember_me] || '1'
 # the next line is the work around for rails version >=5.1
  integration_test = options[:integration_test] || 'false'
  if integration_test == 'true'
    post login_path, params: { session: {  email: user.email,
                                password: password,
                                remember_me: remember_me }
                              }
  else
#      params[:session][:user_id] = user.id
#      session[:user_id] = user.id 
   controller.session[:user_id] = user.id
   # params[session[:user_id] ] = user.id 
  end
end

宝石文件:

source 'https://rubygems.org'

ruby '2.3.0'
gem 'rails',                     '>= 5.0.0.beta1'
gem 'railties',                  '>= 5.0.0.beta1'
gem 'bcrypt',                    '>= 3.1.10'
gem 'faker',                     '>= 1.6.1'
gem 'carrierwave',               '>= 0.10.0'
gem 'mini_magick',               '>= 4.3.6'
gem 'fog',                       '>= 2.0.0.pre.0'
gem 'kaminari', :git => "git://github.com/amatsuda/kaminari.git", :branch => 'master'
gem 'kaminari-bootstrap',        '>= 3.0.1'
gem 'bootstrap-sass',            '>= 3.3.6'
gem 'sass-rails',                '>= 5.0.4'
gem 'uglifier',                  '>= 2.7.2'
gem 'coffee-rails',              '>= 4.1.1'
gem 'jquery-rails',              '>= 4.0.5'
gem 'therubyracer',              '>= 0.12.2'
gem 'turbolinks', github: 'rails/turbolinks'
gem 'jbuilder',                  '>= 2.4'
gem 'sdoc',                      '>= 0.4.1', group: :doc
gem 'net-ssh'

group :development, :test do
  gem 'sqlite3',                  '>= 1.3.11'
  gem 'byebug',                   '>= 8.2.1'
  gem 'spring',                   '>= 1.6.1'
end

group :development do
  gem 'web-console',              '>= 3.0.0'
end

group :test do
  gem 'minitest-reporters',       '>= 1.1.7'
  gem 'mini_backtrace',           '>= 0.1.3'
  gem 'guard',                    '>= 2.13.0'
  gem 'guard-minitest',           '>= 2.4.4'
  gem 'minitest',                 '>= 5.8.3'
  gem 'rails-controller-testing', '>= 0.0.3'
end

group :production do
  gem 'pg',                       '>= 0.18.4'
  gem 'rails_12factor',           '>= 0.0.3'
  gem 'puma',                     '>= 2.15.3'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', '>= 1.2015.7', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

似乎我在当前设置中(参见 gemfile 等)令牌(:destroy、:user 等)的处理方式与我以前的设置(如 mhartl 推荐的)不同,所以我使用的修复方法是用命名路由替换我测试中的所有标记(:user 变成 user_path(@user)。销毁操作似乎没有默认命名路由,所以我在 routes.rb 文件中添加了一个.

我可以通过添加这样的路由来让测试通过:

delete 'delete_user' => 'users#destroy'  

并将测试更改为:

delete delete_user_path params:{id: @user} 

但是,实际站点和测试对同一操作使用不同的路由,所以我不知道我是否可以相信这是最终解决方案。

如果我从用户资源中删除销毁:

resources :users, except: :destroy 

然后页面 link 不工作,但测试仍然通过。我看不到如何在页面 link 上使用添加的 'delete_user(@user) route',我尝试时一直找不到用户,而且我似乎无法让 user#destroy 操作在测试中起作用没有添加的路线。

正确的解决办法是替换为:

delete :destroy, params: { id: @user }

与:

delete user_url(@user)