使用Rails和Rspec的'undefined method'帖子

时间:2013-10-15 09:38:17

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

坚持:

' undefined method `post' for #<Class:0x000001058c0f68> (NoMethodError)'

关于测试控制器create操作。

我正在使用Rails 4,rpsec和Factory Girl

控制器:

def create
  @post = Post.new(post_params)
  @post.user_id = current_user.id

  if @post.save
    flash[:success] = "Yay! Post created!"
    redirect_to root_path
  else
    # flash[:error] = @post.errors.full_messages
    render 'new'
  end
end

测试:

describe '#create' do
  post 'create',  FactoryGirl.attributes_for(:post, user: @user)
  response.should be_successful
end

3 个答案:

答案 0 :(得分:5)

我认为可以在post方法块中访问it方法:

describe 'create' do
  it 'should be successful' do
    post :create, FactoryGirl.attributes_for(:post, user: @user)
    response.should be_success
  end
end

BTW我认为您需要测试重定向,而不是success状态。

答案 1 :(得分:2)

对于偏离主题感到抱歉,但我只是想给你一些建议。

考虑关注best practices并使用RSpec的expect语法而不是应该。在这里阅读更多关于为什么语法不好的想法:http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax

这就是我重写你的例子的方式:

describe 'create' do
  it 'responds with 201' do
    post :create, attributes_for(:post, user: @user)
    expect(response.status).to eq(201)
  end
end

在示例中,我使用FactoryGirl的短语法方法attributes_for而不是FactoryGirl.attributes_for,它节省了几个字节。以下是如何使用简短方法(在spec / test_helper.rb中):

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

我正在测试状态代码201,Rails默认会为成功的创建操作返回(重定向应该是3xx)。这使测试更加具体。

希望对编写更好的规格有任何帮助。

答案 2 :(得分:0)

问题来自于post语句中应使用it的事实。我通常会像这样测试我的控制器:

describe 'POST "create"' do

  let(:user)   { User.new }
  let(:params) { FactoryGirl.attributes_for(:post, user: user) }
  let(:action) { post :create, params }
  let!(:post)  { Post.new }

  before do
    Post.should_receive(:new).and_return(post)
  end

  context 'on success' do

    before do
      post.should_receive(:save).and_return(true)
    end

    it 'renders success' do
      action
      expect(response).to be_success
    end

    it 'redirects' do
      action
      expect(response).to be_redirected
    end

    it 'sets flash message' do
      action
      expect(flash[:success]).to_not be_empty
    end

  end

  context 'on failure' do

    before do
      post.should_receive(:save).and_return(false)
    end

    it 'renders new' do
      action
      expect(response).to render_template(:new)
    end

  end
end