【问题标题】:Test controller method. Rspec测试控制器方法。规格
【发布时间】:2014-08-07 17:36:49
【问题描述】:

我想测试控制器方法,但找不到使用 order 和 search 的测试方法示例。 这是我的控制器:

class Admin::HotelsController < Admin::BaseController
  helper_method :sort_column, :sort_direction
  def index
    @hotels = Hotel.search(params[:search], params[:search_column]).order(sort_column + ' ' + sort_direction)
  end

  def show
    @hotel = Hotel.find(params[:id])

  end

  def update
    @hotel = Hotel.find(params[:id])
    if @hotel.update_attributes(hotel_params)
      redirect_to admin_hotels_path
    else
      render(:edit)
    end
  end

private
  def hotel_params
    params.require(:hotel).permit(:title, :description, :user_id, :avatar, :price, :breakfast, :status, address_attributes: [:state, :country, :city, :street])
  end

  def sort_column
    Hotel.column_names.include?(params[:sort]) ? params[:sort] : 'created_at'
  end

  def sort_direction
    %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
  end
end 

这是对该控制器的测试。

require 'rails_helper'

describe Admin::HotelsController do
    login_admin
    describe 'GET index' do
        it 'render a list of hotels' do
            hotel1, hotel2 = create(:hotel), create(:hotel)
            get :index
            expect(assigns(:hotels)).to match_array([hotel1, hotel2])
        end
    end

  describe 'GET show' do
    it 'should show hotel' do
      @hotel = create(:hotel)
      get :show, { id: @hotel.to_param, template: 'hotels/show' }
      expect(response).to render_template :show
    end
  end


end

我不知道如何测试索引方法。请帮助或给我一个链接,其中包含有关此信息的信息。谢谢!

【问题讨论】:

  • 尝试使用eq 而不是match_array
  • 谢谢,它们的不同之处在于,即使是部分匹配,match_array 也会返回 true?
  • match_arraycontain_exactly 的替代形式,它不关心顺序。

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


【解决方案1】:

如果可能对您有所帮助,出于各种原因,我个人更喜欢对控制器进行最低限度的测试:

1) 当我开始进行 Rails 测试时,我读了很多文章说这是个好主意 2)它允许您在隔离模型方法中进行测试:

describe 'GET index' do
  it 'render a list of hotels' do
    hotel1, hotel2 = create(:hotel), create(:hotel)
    get :index
    expect(assigns(:hotels)).to match_array([hotel1, hotel2])
  end
end 

在这里,您的测试与您对模型的查询结果相匹配。你可以这样拆分:

describe 'GET index' do
  it 'render a list of hotels' do
    hotel1, hotel2 = create(:hotel), create(:hotel)
    Hotel.should_receive(:search).with(YOUR PARAMS)
    get :index
    response.response_code.should == 200
  end
end

然后在模型测试中测试Hotel.search的结果。

3) 它允许您测试功能,而不是一些不相关的随机事物:

describe 'GET show' do
  it 'should show hotel' do
    @hotel = create(:hotel)
    get :show, { id: @hotel.to_param, template: 'hotels/show' }
    expect(response).to render_template :show
  end
end

这里的“expect(response).to render_template :show”似乎是在测试 Rails 渲染系统是否正常工作。我认为这不是您想要测试的,您可能更喜欢(这就是我会做的):

describe 'GET show' do
  it 'should show hotel' do
    @hotel = create(:hotel)
    Hotel.should_receive(:find).with(YOUR PARAMS)
    get :show, { id: @hotel.to_param, template: 'hotels/show' }
    response.response_code.should == 200
  end
end

然后使用类似 capybara gem 的功能测试来测试应该出现在网页上的内容,除非你正在渲染一些 json:在这种情况下,匹配控制器中的 json 值。

顺便说一句:“@hotel = create(:hotel)” 这里不需要@,因为您在“它”中。此外,您可以像这样创建这样的条目:

context "" do
  before(:each) do
    @hotel = create(:hotel)   # here the @ is necessary for the variable to be        
    end                       # accessible in the it
  it "" do
  end
end

甚至像这样:

context "" do
  let(:hotel) { create(:hotel) } # you can call it in the test by using hotel and it
  it "" do                       # will be insert in you db only when it's in the "it"
  end                            # if you want it to be created in the "it" without
end                              # calling hotel for nothing, use let!

【讨论】:

  • 谢谢你的回答,我会努力坚持下去的。
【解决方案2】:

我建议使用

describe 'GET index' do
  let(:hotel1) { create(:hotel) }
  let(:hotel2) { create(:hotel) }

  it 'render index template' do
    get :index
    expect(response).to render_template :index
  end

  it 'render asc ordered hotels' do
    get :index

    # if you are using json responses
    json = JSON.parse(response.body) 
    expect(json['hotels'].first).to eq hotel1
    expect(json['hotels'].last ).to eq hotel2
    # or any similar approach to get test the hotels in response
  end

  it 'render desc ordered hotels' do
    get :index, {direction: 'desc'}

    # if you are using json responses
    json = JSON.parse(response.body) 
    expect(json['hotels'].first).to eq hotel2
    expect(json['hotels'].last ).to eq hotel1
    # or any similar approach to get test the hotels in response
  end

  # you can complete these tests yourself
  it 'render hotels sorted with different_column_than_created_at asc'
  it 'render hotels sorted with different_column_than_created_at desc'

end

【讨论】:

  • 感谢您的回答,或多或少明白了。我有一些问题,当我开始这个测试时,他不工作,因为A JSON text must at least contain two octets! ,但我不知道为什么,因为我确定我的身体有两个以上的八位字节。
  • 你能不能作为response.body 因为我添加了 json 部分作为示例来了解这个想法......而不是实际代码......所以如果你发布 response.body 我可能会能够编辑答案
  • 这个怎么做,请告诉我?
  • 只需在get :index@json = ..... 之前添加p response.body,然后再次运行测试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多