1

Got stuck with:

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

on testing controller create action.

I'm using Rails 4, rpsec, and Factory Girl

Controller:

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

Test:

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

3 回答 3

5

I think post method is accessible inside it method block:

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

BTW I think you need to test for redirect, not success status.

于 2013-10-15T09:40:46.590 回答
2

很抱歉跑题了,但我只是想给你一些建议。

考虑遵循最佳实践并使用 RSpec 的 expect 语法而不是 should。在这里阅读更多关于为什么应该语法是一个坏主意的信息: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)。这使测试更加具体。

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

于 2013-10-15T09:55:50.237 回答
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
于 2013-10-15T09:52:34.387 回答