【问题标题】:Why can't rspec find my no-params-required route?为什么 rspec 找不到我的 no-params-required 路线?
【发布时间】:2020-03-14 04:53:03
【问题描述】:

背景

我正在尝试将旧的 ActionDispatch::IntegrationTest 测试移植到 rspec。

此测试目前正在通过:

require 'test_helper'

class HeartbeatControllerTest < ActionDispatch::IntegrationTest
  test "heartbeat" do
    get "/heartbeat"
    assert_response :success
  end
end

控制器

我有一个HeartbeatController,它返回一个 200:

class HeartbeatController < ApplicationController
  def show
    render(json: { 'status': 'ok' })
  end
end

curl 可以正常工作。

路线

rake routes 显示路线:

                               Prefix Verb   URI Pattern                                                                              Controller#Action
                            heartbeat GET    /heartbeat(.:format)                                                                     heartbeat#show

规格

我的测试非常简单:

require 'rails_helper'

describe HeartbeatController do
  it 'succeeds' do
    get '/heartbeat'
    expect(response).to be_success
  end
end

但是当我运行它时

Failures:

  1) HeartbeatController succeeds
     Failure/Error: get '/heartbeat'

     ActionController::UrlGenerationError:
       No route matches {:action=>"/heartbeat", :controller=>"heartbeat"}
     # ./spec/controllers/heartbeat_controller_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00718 seconds (files took 1.11 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/controllers/heartbeat_controller_spec.rb:4 # HeartbeatController succeeds

问题

  • 为什么这个测试失败了?
  • 我做错了什么?
  • 如果 Stack Overflow 不存在,我该如何进一步调试?

【问题讨论】:

    标签: ruby-on-rails rspec


    【解决方案1】:

    如果这是一个控制器规范,您希望传递方法的名称而不是路由。

    require 'rails_helper'
    
    describe HeartbeatController do
      it 'succeeds' do
        get :show
        expect(response).to be_success
      end
    end
    

    控制器规范实际上并不驱动整个 Rails 堆栈 - 它们只是创建一个模拟请求并将其传递给控制器​​实例并调用控制器上的方法。

    您收到路由错误的原因是ActionController::TestCase::Behavior 尝试验证该给定控制器/方法名称组合的路由是否存在。因此No route matches {:action=&gt;"/heartbeat", :controller=&gt;"heartbeat"}

    众所周知,单元测试控制器的整个过程存在很大缺陷,因为您要模拟框架的大部分内容,而不是实际测试控制器的功能——它们响应 HTTP 请求。由于路由层和中间件堆栈被模拟出来,您的测试不会像真正的集成测试那样覆盖它们。

    Rails and RSpec team discourage directly testing controllers。而是使用request specs,它实际上驱动整个堆栈。

    # spec/requests/heartbeats_spec.rb
    require 'rails_helper'
    
    describe 'Heartbeats', type: :request do
      describe "GET /heartbeat" do
        it 'succeeds' do
          get '/heartbeat'
          expect(response).to be_successful
        end 
      end
    end
    

    【讨论】:

    • 感谢您提供非常彻底和有用的答案。为了使您编写的替换测试正常工作,我必须进行两个小改动:/heartbeats/heartbeat,以及 be_successbe_successful
    • @AaronBrager 对。我很懒,只是复制粘贴了控制器规范并进行了一些小改动。我总是将生成器设置为跳过控制器规范并生成请求规范。希望有一天 RSpec rails 会赶上来,而不是默认生成默认不鼓励的代码。
    • 谢谢!我一直在想为什么我的测试没有正确路由请求。切换到请求规范就可以了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 2019-11-22
    相关资源
    最近更新 更多