1

Please Note: This question may seem similar to my other question, and it is just that...similar. Not identical. I replicated some of the info because it is relevant to the question. That being said, I didn't want to overwhelm either question with too many requests, so I split them up.

I am relatively new to Testing, so please forgive me if this question seems basic.

I am using Rspec, Shoulda, FactoryGirl and Faker. My class is User.

These are the schema & associations for my User model:

# == Schema Information
#
# Table name: users
#
#  id                     :integer          not null, primary key
#  email                  :string(255)      default(""), not null
#  encrypted_password     :string(255)      default("")
#  reset_password_token   :string(255)
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  sign_in_count          :integer          default(0), not null
#  current_sign_in_at     :datetime
#  last_sign_in_at        :datetime
#  current_sign_in_ip     :string(255)
#  last_sign_in_ip        :string(255)
#  created_at             :datetime
#  updated_at             :datetime
#  first_name             :string(255)
#  confirmation_token     :string(255)
#  confirmed_at           :datetime
#  confirmation_sent_at   :datetime
#  unconfirmed_email      :string(255)
#  invitation_relation    :string(255)
#  avatar                 :string(255)
#  invitation_token       :string(255)
#  invitation_created_at  :datetime
#  invitation_sent_at     :datetime
#  invitation_accepted_at :datetime
#  invitation_limit       :integer
#  invited_by_id          :integer
#  invited_by_type        :string(255)
#  invitations_count      :integer          default(0)
#  bio                    :text
#  last_name              :string(255)
#  gender                 :integer          default(0)
#

  has_one :family_tree, dependent: :destroy
  has_many :memberships, dependent: :destroy
  has_many :nodes, dependent: :destroy
  has_many :comments, dependent: :destroy

  enum gender: { male: 0, female: 1 }

  after_create :create_family_tree
  after_destroy :remove_all_memberships
  after_invitation_accepted :send_emails

The methods (which are callbacks) I am unsure of testing are:

  private
    def create_family_tree
      family_tree = self.build_family_tree(name: "#{name}'s Family Tree")
      family_tree.save!
    end

    def remove_all_memberships
      memberships = Membership.includes(:user).where(user_id: self.id)
      memberships.destroy_all
    end

    def send_emails
      invited_user = self
      inviter_user = self.invited_by
      welcome_message = InviteAcceptance.welcome_to_invited_user_after_signing_up(invited_user, inviter_user)
      welcome_message.deliver
      notification_message = InviteAcceptance.notification_that_invited_user_signed_up(inviter_user, invited_user)
      notification_message.deliver
    end

This is my user_spec.rb so far, which just tests the associations and the gender value, both of which are fine:

require 'rails_helper'

describe User do
  it { should have_one(:family_tree) }
  it { should have_many(:memberships) }
  it { should have_many(:nodes) }
  it { should have_many(:comments) }

  it "should return gender from an enum value, where 0 = male, and 1 = female" do
    expect(build(:user).gender).to eq "female"
  end  

end

This is my spec/factories/users.rb

FactoryGirl.define do
  factory :user do
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    email { Faker::Internet.email }
    password { Faker::Internet.password(10) }
    password_confirmation { Faker::Internet.password(10) }
    bio { Faker::Lorem.paragraph }
    invitation_relation { Faker::Lorem.word }
    # required if the Devise Confirmable module is used
    confirmed_at Time.now
    gender 1
  end
end

I guess the real question is, how do I actually write tests for those methods itself and then how do I test the callbacks separately?

Community
  • 1
  • 1
marcamillion
  • 32,933
  • 55
  • 189
  • 380

1 Answers1

2

I would just test the methods normally, not even worrying that they will be used as callbacks. That means establish a known state, perform your operation, and check for the desired state, for each one.

Then, you can use something like shoulda-callback-matchers to verify that the proper callbacks are actually in place without writing a ton of code.

Alternatively, you could simply establish a known state, run your callback method by performing the operation which triggers the callback, and check for the desired state.

Brad Werth
  • 17,411
  • 10
  • 63
  • 88
  • Actually, how do I test a private method? I am now implementing these tests, but I can't call any of the private methods. Thoughts? Actually scratch this question, I googled it and found out that `obj.send(:private_method)` is the way to approach this and it works. Thanks! – marcamillion Apr 27 '15 at 19:46
  • @marcamillion You're welcome - you might enjoy http://stackoverflow.com/a/26284769/525478 – Brad Werth Apr 27 '15 at 20:52