Go back to the main page

How I test against the QuickBooks Online API

 

 


A better way to write your QuickBooks integration code

Are you just "winging it" with your production QuickBooks integration code? Pushing changes and hoping all goes well? Or perhaps you are a bit more righteous and manually test against the sandbox. Even then, why create 30 duplicate invoices when working on some simple QBO API error handling code? I am going to demonstrate in less than 20 minutes how to get your Rails app ready for testing against live QBO API interactions in an automated way. As a baseline I am going to start with my minimulcasts account branch, which is a Rails 4.1 app. That said, most of this tutorial should should translate well for a Rails 3.2 app.

  1. Clone my minimulcasts account branch and switch into it.
  2. $ git clone -b account git@github.com:minimul/minimulcasts.git
    $ cd minimulcasts
    
  3. Update the quickbooks-ruby gem.
  4. $ bundle update quickbooks-ruby
    
  5. Add these to the Gemfile next
  6. group :development do
      gem 'spring'
      gem 'better_errors'
      gem 'spring-commands-rspec'
    end
    
    group :test do
      gem 'rspec-rails'
      gem 'factory_girl_rails'
      gem 'vcr'
      gem 'webmock'
    end
    
    $ bundle install
    
  7. Next, enable spring and spring-rspec commands.
  8. $ bundle exec spring binstub --all
    
  9. Run the rspec install generator.
  10. $ bin/rails g rspec:install
    
  11. Get OAuth tokens from your Intuit developer account.
  12. This is fastest way to get OAuth Creds.
  13. Put those credentials into environmental shell variables.
  14. Open up spec/rails_helper.rb and modify it as such.
  15. This section is at the 6:47 mark.
      
    require 'factory_girl_rails'
    require 'vcr'
    
    VCR.configure do |config|
      config.cassette_library_dir = Rails.root.join('spec', 'vcr')
      config.hook_into :webmock
      config.filter_sensitive_data('<ACCESS_TOKEN>') { URI.encode_www_form_component(ENV['MINIMULCASTS_ACCESS_TOKEN']) }
      config.filter_sensitive_data('<CONSUMER_KEY>') { URI.encode_www_form_component(ENV['MINIMULCASTS_CONSUMER_KEY']) }
    end
    
  16. Also add FactoryGirl syntax methods within the RSpec configure block
  17.   
    RSpec.configure do |config|
      # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
      config.fixture_path = "#{::Rails.root}/spec/fixtures"
      config.include FactoryGirl::Syntax::Methods
    
  18. Create a spec/factories.rb and put in an account factory.
  19. FactoryGirl.define do
      factory :account do
        name 'Tamar Trick'
        qb_token ENV['MINIMULCASTS_ACCESS_TOKEN']
        qb_secret ENV['MINIMULCASTS_ACCESS_TOKEN_SECRET']
        qb_company_id '1292740145'
      end
    end
    
  20. Create a spec/requests directory with a spec called qbo_spec.rb.
  21.   
    require 'rails_helper'
    
    describe 'QBO requests' do
      it 'creates an invoice' do
        account = create(:account)
        base = Quickbooks::Base.new(account, :invoice)
        invoice = base.qr_model(:invoice)
        invoice.customer_id = 2
    
        line_item = base.qr_model(:invoice_line_item)
        line_item.amount = 50
        line_item.description = "Plush Baby Doll"
        line_item.sales_item! do |detail|
          detail.unit_price = 50
          detail.quantity = 1
          detail.item_id = 1
          detail.tax_code_id = 'NON'
        end
    
        invoice.line_items << line_item
        VCR.use_cassette("qbo/invoice/create", record: :all) do
          result = base.service.create(invoice)
          expect(result.id).to eq 159
        end
      end
    end
    
  22. We are ready to run the spec.
  23. $ bin/rspec spec  
    
    Minimul says —

    The first run will take a bit of time as we have on record: :all, which is making a live request to the sandbox. This run will fail because I have hard coded the resulting id back from the API. I use this expectation so to verify that only the recorded cassette is being used when record: :none is invoked on the next run.

    This section is at the 19:02 mark.
  24. After the successful run you can grab the returned ID and stick in the expectation. Then change the record option to :none and re-run the spec.
  25.   VCR.use_cassette("qbo/invoice/create", record: :none) do
        result = base.service.create(invoice)
        expect(result.id).to eq Put in the returned ID you get from the previous run.
      end
      
    
  26. Run the spec again and you will notice how fast it runs as it is using the recorded cassette from VCR.
  27. Finally, take a look at the recorded cassette at spec/vcr/qbo/invoice/create.yml.

Conclusion

Not so bad, eh? Now you can develop integration code in a more assured fashion. This approach can also aid you when working on a PR for the quickbooks-ruby gem as you can take the XML from the cassette and put into a fixture. The code for this tutorial can be found on Github.