10

So I was searching online for a solution, but there seems to be scarce information about testing initializers created in Rails.

At the moment, I've written a pretty large API call-n-store in my config/initializers/retrieve_users.rb file. It makes an API request, parses the JSON, and then stores the data as users. Being pretty substantial, I've yet to figure out the cleanest way to test it. Since I need to retrieve the users before any functions are run, I don't believe I can move this script anywhere else (although other suggestions would be welcomed). I have a couple questions about this:

  1. Do I have to wrap this in a function/class to test my code?
  2. Where would I put my spec file?
  3. How would I format it RSpec-style?

Thanks!

ForgetfulFellow
  • 2,477
  • 2
  • 22
  • 33
  • 3
    This sounds like a bad practice. For instance if the service was down your app would refuse to start until it could connect or it times out and then it would raise an exception more than likely crashing your app. I would rethink where you do this or what you are trying to accomplish – CWitty Aug 05 '14 at 20:02

2 Answers2

7

I just gave this a shot and have passing rspec tests, I am going to further refactor my code and in the end it will be shorter, but here is a snapshot of what I did, using this link as a guide:

The gist of it is this: make a class in your initializer file with the functions you want, then write tests on the functions in the class.

config/initializers/stripe_event.rb

StripeEvent.configure do |events|
  events.subscribe 'charge.dispute.created' do |event|
    StripeEventsResponder.charge_dispute_created(event)
  end
end

class StripeEventsResponder
  def self.charge_dispute_created(event)
    StripeMailer.admin_dispute_created(event.data.object).deliver
  end
end

spec/config/initializers/stripe_events_spec.rb

require 'spec_helper'

describe StripeEventsResponder do
  before { StripeMock.start }
  after { StripeMock.stop }
  after { ActionMailer::Base.deliveries.clear }

  describe '#charge_dispute_created' do
    it "sends one email" do
      event = StripeMock.mock_webhook_event('charge.dispute.created')
      StripeEventsResponder.charge_dispute_created(event)
      expect(ActionMailer::Base.deliveries.count).to eq(1)
    end

    it "sends the email to the admin" do
      event = StripeMock.mock_webhook_event('charge.dispute.created')
      StripeEventsResponder.charge_dispute_created(event)
      expect(ActionMailer::Base.deliveries.last.to).to eq(["admin@example.com"])
    end
  end
end
masukomi
  • 10,313
  • 10
  • 40
  • 49
user3291025
  • 997
  • 13
  • 20
1

Seems like this would be tricky, since the initializers are invoked when loading the environment, which happens before the examples are run.

I think you've already figured out the most important step: move the code into another unit where it can be tested outside of the Rails initialization process. This could be a class or a module. Mock out the network dependencies using webmock.

Where should this code reside? See this (now quite ancient) answer by no less than Yehuda Katz himself. Put the spec file in the corresponding part of the tree; i.e. if the unit ends up in lib/my_class.rb, the spec goes in spec/lib/my_class_spec.rb. You may need to modify spec/rails_helper to load the spec file.

Community
  • 1
  • 1
zetetic
  • 47,184
  • 10
  • 111
  • 119