如何针对需要远程OAuth的代码编写测试?

时间:2016-02-08 18:29:43

标签: ruby-on-rails ruby oauth

我有一些代码使用API​​将某些数据推送到远程第三方服务。

在实际使用中,它需要OAuth生成的凭据才能推送到此API端点。这一切都有效,当用户按下“导出”按钮时,我们将它们重定向到OAuth流程,他们回来了,我们有一个令牌,我们推送数据(可能是在bg工作中,这有它自己的潜在问题,但这不是这个问题的焦点),太好了。

但是如何为此功能编写自动化测试?我在测试时没有OAuth凭据,我不知道是否有任何好方法可以获取它们。

可以实际网络欺骗假冒用户登录真正的第三方服务,但这看起来很难看。我可以跳过实际的“证明它确实推动测试”,并测试我要发送的请求看起来正确,但我希望有一个自动化测试证明它确实如果第三方改变了事情,成功地推动。我 可能会用“vcr”记录它以避免每次网络请求缓慢,但这也不是问题(除非是因为它会让事情变得更难......)

在这种情况下,第三方API使用OAuth 1.0a,如果这很重要。

任何想法或解决方案?这是件事吗?

1 个答案:

答案 0 :(得分:0)

OmniAuth具有内置测试模式,可用于短路实际请求。

OmniAuth.config.test_mode = true

您可以使用以下方式模拟失败:

OmniAuth.config.mock_auth[:some_provider] = :invalid_credentials

或者设置回复:

OmniAuth.config.add_mock(:some_provider, {:uid => '12345'})

您只会在涵盖身份验证系统的测试中执行此操作,例如CallbacksController或覆盖路径登录的集成测试。

对于其他所有内容,您只需存根身份验证系统,以便在应该有经过身份验证的用户时,current_user返回一个fixture(或工厂)。它比每次集成测试重新测试相同的符号路径快得多。 (点击"登录" ...)

如果您正在使用Warden或Devise,他们已经内置了测试帮助程序来执行此操作。

您可以使用VCR录制它,但这会引入有关如何处理可能包含敏感信息的磁带以及如何在开发人员之间共享这些信息的问题。

通常针对实际提供商进行测试更多的是OmniAuth策略作者关注的问题,除非您为某些模糊的OAuth提供程序创建策略或创建自己的OAuth服务,否则您不必担心。如果你正在使用Facebook,Twitter或其他一个大男孩,那么它不是一个问题。

另见:

这是使用omniauth-flickr的项目进行集成测试的示例:

require 'rails_helper'
require 'support/omniauth'

RSpec.feature 'Flickr Authentication' do

  let(:t) { I18n.t }
  let(:sign_in_via_flickr) do
    visit root_path
    click_link t('sessions.menu.sign_in_with_flickr')
  end

  context 'with a successfull flickr auth' do
    before do
       # mock_auth_hash is helper which returns a big hash of fake user data
       OmniAuth.config.add_mock(:flickr, mock_auth_hash)
       OmniAuth.config.mock_auth[:flickr]
    end
    scenario 'when I click log in, I should be logged in via Flickr' do
      sign_in_via_flickr
      expect(page).to have_content t('sessions.flash.you_have_been_signed_in')
    end
    scenario 'I should be logged out' do
      sign_in_via_flickr
      click_link(t('sessions.menu.sign_out'))
      expect(page).to have_content t('sessions.flash.you_have_been_signed_out')
    end
  end
  context 'with a failed authentication' do
    before do
      OmniAuth.config.mock_auth[:flickr] = :invalid_credentials
    end
    scenario 'I should be notified that sign in failed' do
      sign_in_via_flickr
      expect(page).to have_content t('auth.failure.flashes.invalid_credentials')
    end
    scenario 'I should not be logged in' do
      sign_in_via_flickr
      expect(page).to_not have_content(t('sessions.flash.you_have_been_signed_in'))
      expect(page).to_not have_link(t('sessions.menu.sign_out'))
    end
  end
end