Как опубликовать, чтобы создать с помощью метода helper spec в спецификации контроллера? - PullRequest
0 голосов
/ 11 мая 2011

Я относительно новичок в программировании, Rails, Ruby, Rspec и т.п., так что спасибо за вашу помощь!

Мои спецификации были очень повторяющимися, поэтому я написал несколько вспомогательных методов. Я не могу понять, как правильно использовать их в моих спецификациях. В частности, у меня есть пользовательский контроллер с create:

  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to user_path(@user)
    else
      render :action => :new
    end
  end

Бит в помощнике спецификаций, который создает действительного пользователя:

def valid_user_eilif
  @test_image = Rails.root + "spec/fixtures/images/seagull.jpg"
  @file = Rack::Test::UploadedFile.new(@test_image, "image/jpeg")
  user = User.create!(:username => "eilif", :email => "eilif@email.org",
  :image => @file, :bio => "Lots of text that I don't want to write",
  :signature_quote => "Yet more text.")
  user.save!
  user
end

А потом в моей спецификации контроллера пользователя:

before (:each) do
  post :create, :user => valid_user_eilif
end

it 'should assign user to @user' do
  assigns(:user).should eq(User.last)
end

Когда я запускаю спецификацию, я получаю сообщение об ошибке:

 Failure/Error: assigns(:user).should eq(User.last)

   expected #<User id: 1, username: "eilif", email: "eilif@email.org", bio: "Lots of text that I don't want to write", signature_quote: "I feel empty.", image_file_name: "seagull.jpg", image_content_type: "image/jpeg", image_file_size: 10475, image_updated_at: "2011-05-10 23:35:55", created_at: "2011-05-10 23:35:56", updated_at: "2011-05-10 23:35:56">
        got #<User id: nil, username: nil, email: nil, bio: nil, signature_quote: nil, image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil, created_at: nil, updated_at: nil>

Итак, я предполагаю, что я неправильно отправляю сообщение о создании, поскольку ничего не создано? Как правильно это сделать?

Ответы [ 2 ]

1 голос
/ 11 мая 2011

В идеале спецификации контроллера не должны зависеть от модели, способной создать строку в базе данных. С помощью такого простого действия вы можете смоделировать зависимости:

describe UsersController do
  context "on success" do
    before(:each) do
      @user = mock_model(User,:save=>true)
      User.stub(:new) {@user}
      post :create, :user => {}
    end

    it "redirects" do
      response.should redirect_to(user_path(@user))
    end

    it "assigns" do
      assigns[:user].should == @user
    end
  end
  context "on failure" do
    it "renders 'new'" do
      @user = mock_model(User,:save=>false)
      User.stub(:new) {@user}
      post :create, :user => {}
      response.should render_template "users/new"
    end
  end
end

Обратите внимание, что спецификации ничего не передают в params[:user]. Это помогает обеспечить разделение интересов MVC, благодаря чему модель отвечает за обработку атрибутов, т.е. проверка, настройка ассоциаций и т. д. Контроллеры не всегда могут быть «худыми», но это хорошая идея.

0 голосов
/ 11 мая 2011

Похоже, проблема в том, что @user не обновляется после сохранения. Попробуйте assigns(:user).reload.should eql(User.last).

Но есть еще одна небольшая проблема, и она, вероятно, все еще потерпит неудачу. Вы не должны звонить post с :user => valid_user_eilif; вы хотите атрибуты из вашей пользовательской записи, а не сам объект пользователя. По сути, вы создаете нового пользователя в valid_user_eilif, а затем заставляете свой контроллер снова создавать этот объект - если у вас есть какие-то уникальные ограничения, вы получите конфликт.

Это хорошее место, чтобы использовать что-то вроде factory_girl и издеваться. Например, взгляните на то, как один из моих проектов обрабатывает спецификации контроллера. В этом примере используются factory_girl, Mocha и musta . Я буду комментировать это с комментариями ниже:

describe MembersController, "POST create" do
  before do
    # Factory Girl - builds a record but doesn't save it
    @resource = Factory.build(:member)

    # Mocha expectation - overrides the default "new" behavior and makes it 
    # return our resource from above
    Member.expects(:new).with({}).returns(@resource)

    # Note how we expect it to be called with an empty hash; that's from the
    # `:member` parameter to `post` below.
  end

  context "success" do
    before do
      post :create, :member => {}
    end

    # shoulda matchers - check for a flash message and a redirect
    it { should set_the_flash.to(/successfully created/) }
    it { should redirect_to(member_path(@resource)) }
  end

  context "failure" do
    before do
      # Mocha - To test a failing example in the controller, we override the
      # default `save` behavior and make it return false, otherwise it would
      # be true
      @resource.expects(:save).returns(false)
      post :create, :member => {}
    end

    # shoulda matchers - check for no flash message and re-render the form
    it { should_not set_the_flash }
    it { should render_template(:new) }
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...