1
votes

I'm currently working on a Ruby on Rails Application and I'm new to testing. A few day ago I started to write tests using the gems rspec-rails, factory_girl_rails and faker.

Writing tests for model validations was quite easy, but now I'm stuck at writing controller tests. I have a simple class "Message", which I created by using the scaffold command.

SCHEMA:

create_table "messages", force: true do |t|
  t.string   "name"
  t.string   "email"
  t.string   "text"
  t.datetime "created_at"
  t.datetime "updated_at"   end

When I try to run the following test..

spec/controllers/messages_controller_spec.rb:

  describe "POST create" do
    describe "with valid params" do
      it "creates a new Message" do
        expect {
          post :create, FactoryGirl.create(:message)
        }.to change(Message, :count).by(1)
      end
    end
  end

..I get this error message..

MessagesController POST create with valid params creates a new Message (FAILED - 1)

Failures:

1) MessagesController POST create with valid params creates a new Message Failure/Error: expect { count should have been changed by 1, but was changed by 0

..by using this factories:

spec/factories/message.rb:

require "faker"

FactoryGirl.define do
  factory :message do |m|
    m.name { Faker::Name.name }
    m.email { Faker::Internet.email }
    m.text { Faker::Lorem.sentences }
  end
end

I've been searching HOURS for an answer - but so far I haven't found a solution that works for me. I hope anyone out there can help me!

Thanks!

This is my Model: (But even if I remove all validations I get the same error message)

class Message < ActiveRecord::Base
  validates :name, :email, :text,
    presence: { 
      value:  :true,
      message: "ist ein Pflichtfeld"
    }

    validates :name, length: { maximum: 50,
        too_long: "ist zu lang" }

    validates :email, length: { maximum: 50,
        too_long: "ist zu lang" }

    validates :text, length: { maximum: 10000,
        too_long: "ist zu lang" }

end

This is my create action:

  def create

    @message = Message.new(message_params)
    respond_to do |format|
      if @message.save
        format.html { redirect_to action: 'new' }
        format.json { render action: 'show', status: :created, location: @message }
      else
        format.html { render action: 'new' }
        format.json { render json: @message.errors, status: :unprocessable_entity }
      end
    end
  end

Function: message_params

def message_params
  params.require(:message).permit(:name, :email, :text)
end
1
can you show the message model? - Emu
Where is the Message supposed to be created? In the rspec (calling FactoryGirl.create(:message) or in the controller(calling post :create,...)? - Uri Agassi
This is what my Message Model looks like: class Message < ActiveRecord::Base validates :name, :email, :text, presence: { value: :true, message: "ist ein Pflichtfeld" } validates :name, length: { maximum: 50, too_long: "ist zu lang" } validates :email, length: { maximum: 50, too_long: "ist zu lang" } validates :text, length: { maximum: 10000, too_long: "ist zu lang" } end - user1561022

1 Answers

2
votes

Use attributes_for method which returns a hash of attributes that can be used to build an instance of Message.

 describe "POST create" do
    describe "with valid params" do
      it "creates a new Message" do
        expect {
          post :create, FactoryGirl.attributes_for(:message) ## Use attributes_for
        }.to change(Message, :count).by(1)
      end
    end
  end

FactoryGirl.create(:message) would actually save a record in the messages table. For controller testing, you just have to pass a hash of attributes and post :create would call the MessagesController#create action which in turn would save the record in database.

EDIT

Replace m.text { Faker::Lorem.sentences } with m.text { Faker::Lorem.paragraph }. As sentences returns an Array of Strings whereas field text in Model message requires a String. This will result in an error and fail to save the record.

require "faker"

FactoryGirl.define do
  factory :message do |m|
    m.name { Faker::Name.name }
    m.email { Faker::Internet.email }
    m.text { Faker::Lorem.paragraph } ## Use paragraph instead of sentences
  end
end