How do I test this third party API integration in rspec? - ruby-on-rails

My project is a rails app that extends some third party API. A lot of the requests rely on third party API calls. How should I test these cases in rspec? Should I use VCR and actually just hit the third party (then mock future requests)? Or should I just download the payload into a fixture manually and stub requests with webmock and find a way to bypass the oauth process? Are the better solutions?
Note that it uses OAuth, but I don't use omniauth.
Sometimes the API limits me to fetching N records at a time, so I have to paginate them. There could be instances where I'm making 25 requests just to get the data I need, but this is mostly for the sync rake tasks.

There is no need to download a payload manually, as this is exactly what VCR does for you. VCR creates a yaml fixture, that it uses for all future requests.

Related

rails sidekiq shared data

I am designing a messaging system for a rails app that will involve queueing REST API calls to a 3rd party service. I am planning on using sideqik as the queueing mechanism. The 3rd party service uses OAuth for authentication. I am trying to avoid each job having to retrieve a new OAuth token the calls it makes. I would think this is a common issue, but haven't run across any solutions as of yet. It is basically an issue of sharing data between jobs (and threads) and I can understand why that would be a bad idea in general. In this case, however, I think the benefits outweigh the risks. At this point I am thinking of using a singleton object or a helper object that uses fiber-local storage to manage the OAuth token retrieval and caching and letting the worker classes simply use that object to get the token. Is there a simpler or more elegant solution that I am overlooking?

Rails External API Testing

I'm writing tests for my Rails app. My app communicates with an external API that processes customer payments, specifically BrainTree. Now, I want to make sure my app's class that communicates with BrainTree works properly e.g. that it submits user information and other parameters to BrainTree correctly. Making the goal to only test that BrainTree and my App are communicating properly.
One thing to note, is that BrainTree has a sandbox account. To test my class, should I:
Write a feature test using something like Capybara and Rspec and test it from a user's perspective e.g. user logs in, fills out form, submits payment etc.
Write a request spec that just submits the required information and examines the return values. This is what I would prefer but is tricky since BrainTree requires js, and I am not sure I can do have js in a request spec without monkey patching Rspec, which I'd rather not do since I am still fairly new to Rspec and testing in general.
Write both feature and request specs
Write a completely different type of test
I have a feature test in place, but it seems cumbersome to use to just test an external API since it needs to open a browser, fill out forms, etc. in my feature spec I'd rather stub the external API and test the API as a unit test. A request spec seems more efficient but the js requirement seems like a roadblock.
Is there a Best Practice to what I should do in my scenario above?
In general, you don't typically want to write tests only for an external service, but instead for your own code that tests against the responses you receive.
The best way I've found to stub a response from an external API is the VCR gem. This will get a legitimate response and save it for use in future runs. You can erase the stored response occasionally to ensure continued functionality.
Another approach to testing this is to use a fake service that mimics the API. Fake Braintree Gem provides such functionality and I've used this with a mix of VCR for other tests to ensure correct functionality. There's many other approaches but you can test to see which one fits your needs

In Rails, how can I stub a websocket message for a test?

The application is using Minitest on Rails 4 with Capybara.
I'd like to write an integration or feature test that stubs a websocket connection (the application uses Faye as a client) to return a specific message (like I'm used to doing with Webmock).
Is this possible? If so, can you provide an example? My research has not turned up any examples.
Your research hasn't shown up any examples because it's not really what you're supposed to be doing in feature tests. Feature tests are supposed to be end-to-end black box tests where you configure the data as required for the app to generate the desired results and then all interaction is done via the browser (no mocking/stubbing which technically alter your apps code). Additionally when connections between the browser and a 3rd party service are involved there is nowhere in your app where you can mock it.
It may be possible to stub a websocket connection from the browser with a programmable proxy like puffing-billy, however it's generally cleaner to produce a small fake version of the 3rd party service for testing purposes (sinatra app, etc) and point the browser at that rather than the original service when you need to craft custom responses. Additionally, there are a lot of fakes already out there, depending on what service you are using (fake-stripe, fake-s3, etc), which may provide the functionality you're looking for.

Rails tests with various integrations

I have a rails app that interacts with an external api (Salesforce) that relies upon external data sitting in a remote database. I've written a wrapper that wraps this code so that users can just call get_by_id(id) instead of writing the corresponding sql query.
I want to test this code, and I am not sure how I should go about it. Should I be hitting the Salesforce backend database for the tests, calling the real methods? Or should I just mock the results of the method calls? I am perpetually confused by what I should test...
You should write like a suite for Salesforce's interaction.
A basic principle of testing, is that your test should not fail because of external factors. However, your app should be able to recover from SalesForce's errors.
From Rails 4 Test Prescriptions
Unfortunately, interacting with a third-party web service introduces a
lot of complexity to our testing. Connecting to a web service is
slow—even slower than the database connections we’ve already tried to
avoid. Plus, connection to a web service requires an Internet
connection... Some external services are public—we don’t want to post an update to Twitter every time we run our tests, let alone post a credit-card payment to PayPal.
Also, the book has some guidelines,
A fake server, which intercepts HTTP requests during a test and
returns a canned response object. We’ll be using the VCR gem ...* An
adapter, which is an object that sits between the client and the
server to mediate access between them.
A smoke test, which goes from the client all the way to the real server...a full end-to-end test of the entire interaction. We don’t
want to do this often, for all the reasons listed earlier, but it’s
useful to be able to guard against changes in the server API.
An integration test, which goes from the client to the fake server.
This tests the entire end-to-end functionality of our application but
uses a stubbed response from the server.
A client unit test, which starts on the client and ends in the
adapter. The adapter’s responses are stubbed, meaning that the adapter
isn’t even making fake server calls. This allows us to unit-test our
client completely separate from the server API.
An adapter unit test, which starts in the adapter and ends in the
fake server. These tests are the final piece of the chain and allow us
to validate the behavior of the adapter separate from any client or
the actual server
By the way, I think the book is a must-have

How to stub external javascript libraries when writing Rails integration tests/specs?

My app interfaces with Google Maps for geocoding and Stripe for payments. Using VCR I've mocked all requests to these services, which works great. But the libraries for both are still being loaded in javascript_include_tags. What's the best way to deal with this so that integration tests can run completely disconnected from the internet?
If you want to stub the javascript, then why record the interactions in the first place? Am I missing something?
I'm pretty sure geocoding from a test is a violation of the google maps ToS. I think what you want to do is stub the geocoding itself.
Have never used Stripe, but I might take this approach: add a method in a spec helper to cache the Stripe javascript locally, i.e., when a connection is available, download the Stripe javascript. Then in your view load the javascript locally if Rails.env.test?.
For anyone looking for a solution these days, there is a nice gem called Puffing Billy.
Similarly to how VCR allows you to record and replay external requests made by your server code, this library allows you to do the same for external requests made by your client code.

Resources