What is the best way to mock a 3rd party object in ruby?

I'm writing a test app using the twitter gem and I'd like to write an integration test but I can't figure out how to mock the objects in the Twitter namespace. Here's the function that I want to test:

def build_twitter(omniauth)
  Twitter.configure do |config|
    config.consumer_key = TWITTER_KEY
    config.consumer_secret = TWITTER_SECRET
    config.oauth_token = omniauth['credentials']['token']
    config.oauth_token_secret = omniauth['credentials']['secret']
  end
  client = Twitter::Client.new
  user = client.current_user
  self.name = user.name
end

and here's the rspec test that I'm trying to write:

feature 'testing oauth' do
  before(:each) do
    @twitter = double("Twitter")
    @twitter.stub!(:configure).and_return true
    @client = double("Twitter::Client")
    @client.stub!(:current_user).and_return(@user)
    @user = double("Twitter::User")
    @user.stub!(:name).and_return("Tester")
  end

  scenario 'twitter' do

    visit root_path
    login_with_oauth

    page.should have_content("Pages#home")
  end
end

But, I'm getting this error:

1) testing oauth twitter
   Failure/Error: login_with_oauth
   Twitter::Error::Unauthorized:
     GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
   # ./app/models/user.rb:40:in `build_twitter'
   # ./app/models/user.rb:16:in `build_authentication'
   # ./app/controllers/authentications_controller.rb:47:in `create'
   # ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
   # ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'

The mocks above are using rspec but I'm open to trying mocha too. Any help would be greatly appreciated.

OK, I managed to figure this out thanks to everyone's help. Here's the final test:

feature 'testing oauth' do
  before(:each) do
    @client = double("Twitter::Client")
    @user = double("Twitter::User")
    Twitter.stub!(:configure).and_return true
    Twitter::Client.stub!(:new).and_return(@client)
    @client.stub!(:current_user).and_return(@user)
    @user.stub!(:name).and_return("Tester")
  end

  scenario 'twitter' do

    visit root_path
    login_with_oauth

    page.should have_content("Pages#home")
  end
end

The trick was figuring out that I needed to stub :configure and :new on the real objects and stub :current_user and :name on a dobuled object instance.


I think the problem is just the way you are using the mock, you created the mock @twitter, but you never actually use it. I think you may be under the impression that any calls to Twitter will use the stubbed methods you specified, but that's not how it works, only calls made to @twitter are stubbed.

I use double ruby, not rspec mocks, but i believe you want to do something like this instead:

Twitter.stub!(:configure).and_return true
...
Twitter::Client.stub!(:current_user).and_return @user

This ensures that anytime the methods you stubbed on Twitter, Twitter::Client are called, they respond how you want.

Also, it seems strange that this is tested as part of a view, should really be part of a controller test instead unless i'm missing something.


You can try using something like http://jondot.github.com/moxy/ . Mock Web Requests

链接地址: http://www.djcxy.com/p/56462.html

上一篇: 访问者无法在接受访问

下一篇: 用ruby模拟第三方对象的最佳方法是什么?