简体   繁体   English

我应该如何使用rspec测试路由和控制器?

[英]How should I test routes and controllers with rspec?

I have just one spec, located at spec/controllers/statuses_spec.rb 我只有一个规格,位于spec/controllers/statuses_spec.rb

Here is its contents: 这是它的内容:

require 'spec_helper'

describe StatusesController do
    describe "routing" do

    it "routes to #index" do
        get("/statuses").should route_to("statuses#index")
    end

  end
end

Suffice to say, I have a simple statuses scaffold, and the statuses controller has the standard actions for CRUD, including an index action. 可以说,我有一个简单的状态脚手架,状态控制器具有CRUD的标准动作,包括索引动作。

However, I get this failure when running the above test: 但是,在运行上述测试时我遇到了这个问题:

15:39:52 - INFO - Running: ./spec/controllers/statuses_spec.rb:6
Run options: include {:locations=>{"./spec/controllers/statuses_spec.rb"=>[6]}}
F

Failures:

  1) StatusesController routing routes to #index
     Failure/Error: get("/statuses").should route_to("statuses#index")
     ActionController::UrlGenerationError:
       No route matches {:controller=>"statuses", :action=>"/statuses"}
     # ./spec/controllers/statuses_spec.rb:8:in `block (3 levels) in <top (required)>'

Finished in 0.21772 seconds
1 example, 1 failure

Rspec makes the assumption that I'm dealing with the statuses controller, which is sort of intuitive I guess because I referenced it in my spec's describe block, and it thinks the string I've passed into the get method ('/statuses') is the function. Rspec假设我正在处理statuses控制器,我觉得这很直观,因为我在规范的描述块中引用了它,它认为我已经传入get方法的字符串('/ statuses')是功能。

Frankly I don't really like this. 坦率地说,我真的不喜欢这个。 I want to be able to test the exact string that is in the URL bar is going to the right controller#action pair. 我希望能够测试URL栏中的确切字符串是否转到右侧控制器#action对。 Regardless, I do as rspec says and do this: 无论如何,我按照rspec说并做到这一点:

require 'spec_helper'

describe StatusesController do
    describe "routing" do

    it "routes to #index" do
        get("index").should route_to("statuses#index")
    end

  end
end

However, now I get this: 但是,现在我明白了:

Run options: include {:locations=>{"./spec/controllers/statuses_spec.rb"=>[6]}}
F

Failures:

  1) StatusesController routing routes to #index
     Failure/Error: get("index").should route_to("statuses#index")
     NoMethodError:
       undefined method `values' for #<ActionController::TestResponse:0x00000102bd3208>
     # ./spec/controllers/statuses_spec.rb:8:in `block (3 levels) in <top (required)>'

Finished in 0.31019 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/controllers/statuses_spec.rb:6 # StatusesController routing routes to #index

I'm getting a no method error regarding a values method. 关于values方法,我得到一个no方法错误。 Values? 值? Seriously, just what? 说真的,到底是什么? I have no idea why I'm getting this error. 我不知道为什么我会收到这个错误。 Here's my spec helper: 这是我的规范助手:

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rspec'

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)

RSpec.configure do |config|
  # ## Mock Framework
  #
  # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
  #
  # config.mock_with :mocha
  # config.mock_with :flexmock
  # config.mock_with :rr
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    Capybara.run_server = true
    Capybara.javascript_driver = :webkit
    Capybara.default_selector = :css
    Capybara.server_port = 7171
    DatabaseCleaner.start
  end

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

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

  config.include RSpec::Rails::RequestExampleGroup, type: :feature

  # 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.use_transactional_fixtures = true

  # If true, the base class of anonymous controllers will be inferred
  # automatically. This will be the default behavior in future versions of
  # rspec-rails.
  config.infer_base_class_for_anonymous_controllers = false

  # Run specs in random order to surface order dependencies. If you find an
  # order dependency and want to debug it, you can fix the order by providing
  # the seed, which is printed after each run.
  #     --seed 1234
  config.order = "random"
end

Testing routes, especially standard RESTful routes, is not standard practice. 测试路由,尤其是标准RESTful路由,不是标准做法。

a) You don't want to waste effort retesting Rails' routing functionality a)您不想浪费时间重新测试Rails的路由功能

b) Your controller or request specs should fail when they cannot route a request b)当您的控制器或请求规范无法路由请求时,它们将失败

More often that not, writing and maintaining routing tests does not give much value and increased confidence. 更常见的是,编写和维护路由测试不会带来太多价值和增加信心。 Consider testing routes when they become complex and error-prone. 考虑在路线变得复杂且容易出错时进行测试。

That said, RSpec provides a route_to matcher for specifying that a request is routable. 也就是说,RSpec提供了一个route_to匹配器,用于指定请求是可路由的。

The recommended place for your routing specs is under spec/routing , though it's not uncommon to see routing specs alongside controller specs. 路由规范的推荐位置是在spec/routing ,尽管在控制器规范中查看路由规范并不罕见。 For example 例如

describe VersionsController do
  describe 'routing' do
    it 'routes GET /version to VersionsController#show' do
      expect(get: '/version').to route_to(controller: 'versions', action: 'show')
    end
  end
end

The shoulda-matchers gem has its own route matcher, allowing you to write tests such as shoulda-matchers gem有自己的路由匹配器,允许你编写测试,如

describe PostsController do
  it { should route(:get, '/posts').to(action: :index) }
  it { should route(:get, '/posts/1').to(action: :show, id: 1) }
end

Routes should be done as part of integration tests. 路由应作为集成测试的一部分完成。 Integration tests are where you test the important work flows of your application - more specifically whether a URL is defined or not seems to be an important workflow. 集成测试是测试应用程序的重要工作流程的地方 - 更具体地说,是否定义了URL似乎是一个重要的工作流程。

Your integration test would look like any normal integration test: 您的集成测试看起来像任何正常的集成测试:

require 'test_helper'
class RoutesTest < ActionController::IntegrationTest
   test "route test" do
       assert_generates "/videos/5", { :controller => "videos", :action => "show", :id => "1" }
       assert_generates "/about", :controller => "pages", :action => "about"
   end
end

As to @jemminger's response of not testing routes - While it is Rail's tests that verify that routes.rb works, it's not Rail's responsibility to test whether http://yoursite.com/users is defined in your routes. 至于@ jemminger没有测试路线的反应 - 虽然铁路公司的测试确认routes.rb有效,但是铁路公司没有责任测试路线中是否定义了http://yoursite.com/users The caveat is that most route testing could be done in existing integration tests, so specific tests for routes could be redundant. 需要注意的是,大多数路由测试可以在现有的集成测试中完成,因此对路由的特定测试可能是多余的。

The specific use case I can think of are all the people that have already, or are going to upgrade from Rails 2 to Rails 3. The code to define routes has changed significantly, and it's better to find out from tests that the routes were upgraded correctly, than from users when they report 404 errors. 我能想到的特定用例是已经或将要从Rails 2升级到Rails 3的所有人。定义路由的代码已经发生了显着变化,最好从测试中找出路由已经升级正确,而不是用户报告404错误时。

it { expect(put: "/posts/1").to route_to(controller: "posts", action: "update", id: "1") }

it { expect(GET: "/posts/1").to route_to(controller: 'posts', action: 'show', id: "1") }

if { expect(get: '/posts').to route_to(controller: 'posts', action: 'index') }

If there is no routes for delete 如果没有删除路由

it { expect(delete: "/posts/1").to_not be_routable }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM