Fake call to a web service in all cucumber tests - ruby-on-rails

My Rails app makes a call to a web service.
I am using the FakeWeb gem to fake these calls in some tests by registering the URI like this:
FakeWeb.register_uri(:get, "http://webservice.com/param?value=a", :response => fake_response)
How can I set this fake registration for the entire test environment, as opposed to setting it up manually for each test ?

Most likely, putting that in your spec/spec_helper.rb file will do the trick. I haven't used FakeWeb, myself, but that's where you'd put any global initialization.

Take look at VCR rubygem.
It records your test suite's HTTP interactions and replays them during test run.

In a file in spec/support/, make a call to register_uri inside a Before block:
Before do
FakeWeb.register_uri(:get, "http://webservice.com/param?value=a", :response => fake_response)
end
I use this trick to set up mock responses using webmock, and it works like a charm.

Related

Restricting VCR to specs

Is there a way to make VCR active only when called via rspec in a Rails app? It works great for my tests, but I don't want it to intercept requests when outside of those tests.
I get Real HTTP connections are disabled if I use a client to connect to the my app and the app is calling an external web service.
Thanks,
Marc
make sure that your VCR gem is set in the proper group
# Gemfile
group :test do
......
gem 'vcr'
end
take a look at http://natashatherobot.com/vcr-gem-rails-rspec/ for more help.
I finally got this work as desired with Rails. I was able to disable VCR (WebMock, actually, which is the backend I chose for VCR) except when I'm running rspec. For background, I initially followed the instructions here when setting up VCR.
First, I create config/initializers/webmock.rb:
# Disable WebMock globally so it doesn't interfere with calls outside of the specs.
WebMock.disable!
Then I added the following around VCR.use_cassette() (in my case this is in spec_helper.rb:
config.around(:each, :vcr) do |example|
name = example.metadata[:full_description].split(/\s+/, 2).join("/").underscore.gsub(/[^\w\/]+/, "_")
options = example.metadata.slice(:record, :match_requests_on).except(:example_group)
+ # Only enable WebMock for the specs. Don't interfere with calls outside of this.
+ WebMock.enable!
VCR.use_cassette(name, options) { example.call }
+ WebMock.disable!
end
Hope that helps someone.

Rails application settings and tests

In my app I've used SettingsLogic to handle the app's settings (such as facebook tokens etc.) which is a gem that basically parses the config/application.yml file and provides easy access to its content.
I've also used this configuration file to enable or disable i18n support for the entire app, as the app is more of a core app for many child apps.
And so in my routes.rb I do things like :
if Settings.i18n.enabled
match ':this', :to => 'that#place'
end
Or in models :
if Settings.i18n.enabled
scope :for_current_locale, lambda { where(:locale => I18n.locale) }
end
I'd like to test how the app responds to both states : when i18n is turned off and when it is turned on.
My problem is that the state is read from the configuration file when Rails initializes. So when I run my tests I could only run tests related to i18n.enabled being false, then change my configuration file and run tests related to i18n.enabled being true.
Is there some way I could reinitialize the app between 2 tests ? (I'm using Rspec)
Or should I automate some way of running 2 separate tests files for both i18n cases ?
Or maybe there is a better way ?
Thanks !
EDIT
As for the routes issue I managed to make the specs pass by changing my settings and reloading the routes explicitly :
before(:all) do
Settings.i18n["enabled"] = true
My::Application.reload_routes!
end
But still I feel this is not ideal, and what about things defined in models ? Can I reload my models as well before running specs ? Won't that duplicate stuff like callbacks ?
I think you simple can reconfigure your Application like following, for example in a rspec before_all block in your specific test file:
YourAppName::Application.configure do
config.i18n.enabled = true # or false
end
And in an after_all block you can set the configuration back to your default one.
I think that could work.

How to mock JSONP call in rspec request spec with capybara?

I'm working on integration my rails application with Recurly.js.
Before I was making requests to recurly from my server side application, therefore I was able to stub all my integration with excellent VCR gem (https://github.com/myronmarston/vcr) but Recurly.js makes request directly to the service from javascript code using JSONP.
The question is: how to mock these jsonp calls in the integration test?
Currently I'm using rspec + capybara + phantomjs driver (https://github.com/jonleighton/poltergeist)
The only approach I came up with is on-the-fly javascript patching. As far as the Poltergeist gem has a method to execute javascript right in the test browser, you could apply the following patch to turn Recurly.js into the test mode:
# The original 'save' function performs JSONP request to Recurly.
# A token is borrowed during the real API interaction.
page.driver.execute_script("""
Recurly.Subscription.save = function (options) {
Recurly.postResult('/subscription', { token: 'afc58c4895354255a422cc0405a045b0' }, options);
}
""")
Just make a capybara-macros, give a fancy name like 'stub_recurly_js' to it and invoke every time before submitting the Recurly.js forms.
Here is also a link to the original post if you want to dig a little deeper: http://pieoneers.tumblr.com/post/32406386853/test-recurlyjs-in-ruby-using-rspec-capybara-phantomjs
Use puffing-billy. It injects a proxy server between your test browser and the outside world, and allows you to fake responses for specific URLs.
Example:
describe 'my recurly jsonp spec' do
before do
# call proxy.stub to setup a fake response
proxy.stub 'https://api.recurly.com/v2/foo', :jsonp => { :bar => 'baz' }
end
it 'does something with recurly' do
....
end
end

How to stub in Rails development environment?

I'm looking for a reliable way to dynamically stub certain methods in my development environment. One example use case is when I need to do development that normally requires access to the Facebook Graph APIs but I don't have Internet access. I'd like to be able to stub the calls to fb_graph methods so it looks as if I'm authenticated and have profile data. Ideally I could turn the stubs on or off with a minor config change.
Any ideas? I'm assuming something like mocha can handle this?
You can use the VCR gem which will record the results of an initial HTTP request into a yml file and then use the contents of that yml file on subsequent http requests. It can then be configured to ignore the VCR logic and always make HTTP requests, if so desired:
https://www.relishapp.com/myronmarston/vcr
Mocha can certainly do it. But it feels a bit strange.
You could also do something like dependency injection.
For instance:
class User < AR::Base
def find_friends
Facebook.find_friends(facebook_id)
end
end
class Facebook
def self.find_friends(id)
# connect to Facebook here
end
end
class FakeFacebook
def self.find_friends(id)
# a fake implementation here
end
end
And inside an initializer:
if Rails.env.development?
User::Facebook = FakeFacebook
end

Rails Functional Test Case and Uploading Files to ActionDispatch::Http::UploadFile

I'm am adding tests to a Rails app that remotely stores files. I'm using the default Rails functional tests. How can I add file uploads to them? I have:
test "create valid person" do
post(:create, :person => { :avatar => fixture_file_upload('avatar.jpeg') })
end
This for some reason uploads a Tempfile and causes the AWS/S3 gem to fail with:
NoMethodError: undefined method `bytesize' for Tempfile
Is their any way that I can get the test to use an ActionDispatch::Http::UploadedFile and perform more like it does when testing with the web browser? Is fixture_file_upload the way to test uploading files to a controller? If so why doesn't it work like the browser?
As a note, I really don't want to switch testing frameworks. Thanks!
I use the s3 gem instead of the aws/s3 gem. The main reasons for this are no support for european buckets and development of aws/s3 seems to be stopped.
If you want to test file upload than using the fixtures_file_upload method is correct, it maps directly to Rack::Test::UploadedFile.new (you can use this if the test file isn't in the fixtures folder).
But I've also noticed that the behavior of the Rack::Test::Uploaded file objects isn't exactly the same as the ActionDispatch::Http::UploadedFile object (that's the class of uploaded files). The basic methods (original_filename, read, size, ...) all work but there are some differences when working with the file method. So limit your controller to these methods and all will be fine.
An other possible solution is by creating an ActionDispatch::Http::Uploaded file object and using that so:
upload = ActionDispatch::Http::UploadedFile.new({
:filename => 'avatar.jpeg',
:type => 'image/jpeg',
:tempfile => File.new("#{Rails.root}/test/fixtures/avatar.jpeg")
})
post :create, :person => { :avatar => upload }
I'd recommend using mocks.
A quick google search reveals:
http://www.ibm.com/developerworks/web/library/wa-mockrails/index.html
You should be able to create an object that will respond to the behaviors you want it to. Mostly used in a Unit test environment, so you can test your stuff in isolation, as integration tests are supposed to fully exercise the entire stack. However, I can see in this case it'd be useful to mock out the S3 service because it costs money.
I'm not familiar with the AWS/S3 gem, but it seems that you probably aren't using the :avatar param properly. bytesize is defined on String in ruby1.9. What happens if you call read on the uploaded file where you pass it into AWS/S3?

Resources