So I have the following module for handling the fetching of and saving of tweets. This is all done on a thread, I am interested in testing two methods with in this module: fetch_tweets
and save_tweets
For fetch_tweets
, I want to validate that the save_tweets
method is called. I don't care what it returns.
For the save_tweets
, I want to test that a tweet is actually saved.
So with that in mind, lets look at some code.
Twitter::TwitterHandler - This lives in lib/twitter/twitter_handler.rb
module Twitter
module TwitterHandler
def handle_tweets(twitter_client_object)
Thread.new do
begin
twitter_lock(twitter_client_object)
ensure
ActiveRecord::Base.clear_active_connections!
end
end
end
def twitter_lock(twitter_client_object)
TwitterTweet.with_advisory_lock('aisis-writer-tweets', 0) do
fetch_tweets(twitter_client_object)
end
end
def fetch_tweets(twitter_client_object)
Rails.cache.fetch([:aisis_twitter_feed, Time.now.to_i/60/5], expires_in: 1.minute){
twitter_client.user_timeline(user_id: '252157965', count: 100).map(&:as_json).select{ |h| h["text"].match(/aisiswriter/i) }.take(10).each do |tweet|
save_tweets(tweet['id_str'], tweet['text'], tweet['created_at'])
end
}
end
def save_tweets(id, text, created_at)
tweet = TwitterTweet.find_or_initialize_by(id: id)
tweet.text = text
tweet.created_at = created_at
tweet.save
end
end
end
twitter_handler_spec.rb - This lives in spec/twitter/twitter_handler_spec.rb
require 'rails_helper'
require_relative '../../lib/twitter/twitter_handler'
describe 'TwitterHandler' do
context "fetch tweets method" do
it "should fetch some tweets" do
t = Time.parse("01/01/2010 10:00")
Time.should_receive(:now).and_return(t)
expect(fetch_tweets(twitter_client)).to receive(:save_tweets).with('342', 'Something', t).and_return nil
end
end
end
When I run bin/rspec spec/twitter/twitter_handler_spec.rb
I get:
Failures:
1) TwitterHandler fetch tweets method should fetch some tweets
Failure/Error: expect(fetch_tweets(twitter_client)).to receive(:save_tweets).with('342', 'Something', t).and_return nil
NoMethodError:
undefined method `fetch_tweets' for #<RSpec::ExampleGroups::TwitterHandler::FetchTweetsMethod:0x007ff1c724e300>
# ./spec/twitter/twitter_handler_spec.rb:11:in `block (3 levels) in <top (required)>'
How do I fix this, so I can call this method and any other method in this module?
You can't call instance methods of a module. You must include
or extend
the module and then call the methods on the object which included or extended the module. The error you are getting from rspec is because you're calling fetch_tweets
from within your example, but fetch_tweets
is not defined within the example.
Once you solve the problem of invoking fetch_tweets
, then you've got to deal with the fact that your expect(fetch_tweets(...))
expectation is saying that the object returned by fetch_tweets
is going to receive a method call of :save_tweets
, which is not what you want. Per your description, you want to set an expectation that whatever object included or extended TwitterHandler
will receive save_tweets
and then you want to call fetch_tweets
.
If this isn't clear, I suggest you read up on Ruby module methods and then read up on RSpec.