Reputation: 45
We are maintaining several Rails-Apps which all pose a similar problem that we don't have a really good solution to: All these apps contain models that need to make a API-Call to an external service in their lifecycle.
Possible cases:
What we exprienced to NOT be a good solution: Adding these calls to the after_*
callbacks of the model. Since that breaks tests fast, cause all factories now have to deal with the api-calls.
I'm looking for a good way to organize these API-call. How do you guys do this?
Ideas we came up with, which I considered not real ideal:
Upvotes: 0
Views: 644
Reputation: 45
This is how I now did it, after the advise:
In Foo
:
class Foo < ActiveRecord::Base
before_save Foo::DataSync
end
Foo:DataSync
looks like this:
class Foo::DataSync
def self.before_save(foo)
...do the API-Calls...
end
end
Now for testing in rspec I added this:
To spec_helper.rb
:
config.before(:each) do
Foo::DataSync.stub(:before_save)
end
Note that config.before(:suite)
will not work, since Foo:DataSync
is not loaded at that time.
Now foo_spec.rb
contains just this:
describe Foo do
let(:foo) {create(:foo)}
it "will sync its data before every save" do
expect(Foo::DataSync).to receive(:before_save).with(foo)
foo.save
end
end
The Foo::DataSync
can be tested like this:
describe Foo::DataSync do
let!(:foo) {create(:foo)}
before do
Foo::DataSync.unstub(:before_save)
end
after do
Foo::DataSync.stub(:before_save)
end
describe "#before_save" do
...my examples...
end
end
Upvotes: 1
Reputation: 19228
If you are concerned about testing you could put the callback methods into a separate class and mock the callback class during testing. Here's an example using RSpec, given the following Foo
and FooCallbacks
classes:
class Foo < ActiveRecord::Base
after_save FooCallbacks
end
class FooCallbacks
def self.after_save
fail "Call to external API"
end
end
You can write and successfully run a spec like this:
describe Foo do
before do
allow(FooCallbacks).to receive(:after_save)
end
it "should not invoke real APIs" do
Foo.create
end
end
Upvotes: 2