0

In this previous question I asked how to build a test for a Post and User model. I would like to now test a third model called Comment.

schema.rb:

  create_table "posts", :force => true do |t|
    t.string   "title"
    t.string   "content"
    t.integer  "user_id"
    t.datetime "created_at",                               :null => false
    t.datetime "updated_at",                               :null => false
    t.integer  "comments_count",        :default => 0,     :null => false
    t.datetime "published_at"
    t.boolean  "draft",                 :default => false
  end

  create_table "comments", :force => true do |t|
    t.text     "content"
    t.integer  "post_id"
    t.integer  "user_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

I specially want to test the comments_count: a want to create comments in a post. Their association had been already made (post has_many comments). and check if comments_count increases.

Can anyone give me an example of how the test would look like?

Current code:

comment.rb:

class Comment < ActiveRecord::Base
  attr_accessible :content, :user_id

  belongs_to :post, :counter_cache => true
  belongs_to :user
end

spec/factories:

FactoryGirl.define do
  factory :user do
    username     "Michael Hartl"
    email    "michael@example.com"
    password "foobar"
    password_confirmation "foobar"
  end
end

FactoryGirl.define do
  factory :post do
    title     "Sample Title"
    content    "Sample Content"
    published_at Time.now()
    comments_count 0
    draft false
    association :user
  end
end

spec/models/post_spec.rb:

require 'spec_helper'

describe Post do
  let(:post) { FactoryGirl.create(:post) }

  subject { post }

  it { should respond_to(:title) }
  it { should respond_to(:content) }
  it { should respond_to(:user_id) }
  it { should respond_to(:user) }
  it { should respond_to(:published_at) }
  it { should respond_to(:draft) }
  it { should respond_to(:comments_count) }

  its(:draft) { should == false }

  it { should be_valid }
end

(By the way, this is my first time testing something in my app. Am I testing something that doesn't need testing? Is there something missing that should?)

Community
  • 1
  • 1
alexchenco
  • 53,565
  • 76
  • 241
  • 413
  • I'm curious about :comment_count. Do you have a reason why you are not using the built in query @post.comments.count? – Kevin K Oct 25 '12 at 07:27
  • @new2ruby `:counter_cache => true` improve performance. The count is cached and there is only a query when are changes. – alexchenco Oct 25 '12 at 07:47
  • Is performance a huge consideration at this point? The guy who has been helping me with rails keeps harping on me that I shouldn't spend time optimizing things which may never become an issue. And even though I find it annoying when he does this, I feel compelled to annoy you in the same way. :) – Kevin K Oct 25 '12 at 07:56
  • @KevinM Ha, well, if I hadn't done it, I would probably forget to do it the future. – alexchenco Oct 25 '12 at 08:15

1 Answers1

2

We may need a factory for comments:

FactoryGirl.define do
  factory :comment do
    content "Sample comemnt"
    association :user
    association :post
  end
end

The following test (which I'd put in the request tests) will check to make sure a comment is actually added when a user adds something to the form and clicks the right button:

describe "New comments" do
  let(:post) FactoryGirl.create(:post)
  let(:user) FactoryGirl.create(:user)

  context "valid with content comment added to database" do

    before do
      visit post_path(post)
      fill_in 'Content', with: "A new comment."
    end

    expect { click_button 'Create Comment' }.to change(Comment, :count).by(1)
  end
end

This test might be good for the comment model specs:

describe Comment do
  let(:comment) { FactoryGirl.create(:comment) }

  subject { comment }

  it { should respond_to(:content) }
  it { should respond_to(:user_id) }
  it { should respond_to(:user) }
  it { should respond_to(:post_id) }

  it { should be_valid }

  it "should belong to a post which has a comment count of 1" do
    comment.post.comment_count.should equal 1
  end
end

The way to then make this test pass is to put something in the comment model so that when a new comment is created, it updates the comment_count attribute in the post that it belongs to.

I'm not 100% sure that the last test there is written correctly. I'm not sure if you can override the previously defined subject.

Kevin K
  • 2,191
  • 2
  • 28
  • 41