Chris Hough
Chris Hough

Reputation: 3558

testing with rspec codeschool level 5 challenge 3

Here is the base question for the test:

Update the spec so that whenever a tweet is created, we verify that email_tweeter is called on the tweet object.  ***I can not alter the models, question, or mailer.***

Models:

# tweet.rb
class Tweet < ActiveRecord::Base
  belongs_to :zombie
  validates :message, presence: true
  attr_accessible :message

  after_create :email_tweeter

  def email_tweeter
    ZombieMailer.tweet(zombie, self).deliver
  end
  private :email_tweeter
end

# zombie.rb
class Zombie < ActiveRecord::Base
  has_many :tweets
  validates :email, presence: true
  attr_accessible :email
end

Mailer:

class ZombieMailer < ActionMailer::Base
  def tweet(zombie, tweet)
    mail(:from => '[email protected]',
         :to => zombie.email,
         :subject => tweet.message)
  end
end

I keep bouncing around on this and could use a few pointers. Here is what I have been working with now: UPDATED

describe Tweet do
  context 'after create' do
    let(:zombie) { Zombie.create(email: '[email protected]') }
    let(:tweet) { zombie.tweets.new(message: 'Arrrrgggghhhh') }

    it 'calls "email_tweeter" on the tweet' do
      tweet.email_tweeter.should_receive(:zombie)
      tweet.save
    end
  end
end

And the error message is:

Failures:

1) Tweet after create calls "email_tweeter" on the tweet
Failure/Error: tweet.email_tweeter.should_receive(:zombie)
NoMethodError:
private method `email_tweeter' called for #<Tweet:0x000000062efb48>
# zombie_spec.rb:7:in `block (3 levels) '

Finished in 0.26328 seconds
1 example, 1 failure

Failed examples:

rspec zombie_spec.rb:6 # Tweet after create calls "email_tweeter" on the tweet

Any rspec peeps out there can point me in the right direction as to what I am missing here? Thank you.

Upvotes: 0

Views: 163

Answers (3)

Kirti Thorat
Kirti Thorat

Reputation: 53018

How about this:

it 'calls "email_tweeter" on the tweet' do
  tweet.should_receive(:email_tweeter)
  tweet.save
end

Upvotes: 1

BroiSatse
BroiSatse

Reputation: 44675

Remove:

  private :email_tweeter

You can't test private methods.

Update:

In fact you can test private methods (with send or eval methods which do not care about privacy), but you shouldn't, as those are part of implementation not the final output. In your tests you should rather save a new tweet an check that email has been sent. implementation details can change with time, it shouldn't affect tests as long as the mail is being send. You can for example try:

it 'generates and sends an email' do
  tweet.save
  ActionMailer::Base.deliveries.last.message.should eq tweet.message
end

Upvotes: 0

Paritosh Piplewar
Paritosh Piplewar

Reputation: 8122

do this

it 'calls "email_tweeter" on the tweet' do
  tweet.email_tweeter.should_receive(:zombie)
  tweet.save
end

Upvotes: 0

Related Questions