Testing Rails Plugin Config Preferences
Published 29 January 10 by Justin French
Time to start blogging again, I hope! Most plugins and Ruby gems have configurable preferences, and usually they’re implemented as a Module or Class attribute, something like this:
class AwesomeGem
cattr_accessor :something
@@something = true
end
In the case of a Rails plugin or gem, these are then modified with an initializer as Rails boots up:
AwesomeGem.something = false
Despite my best efforts to be opinionated, Formtastic has about 15 preferences today, and I can see another 10 or so on the horizon. They all need to be tested. For a while there, we had some pretty brittle tests that did this sort of stuff:
describe AwesomeGem, "something preference" do
describe "when true" do
it "should..." do
AwesomeGem.something = true
# ...
end
end
describe "when false" do
it "should..." do
AwesomeGem.something = false
# ...
end
end
end
The problem here is that we’ve changed AwesomeGem.something’s configuration from true (the default in the class) to false. Any tests that assume the default preference will fail. Maybe. Who knows. Depends on the order your tests run.
So we need to return the preference to it’s default state at the end of any tests that alter it:
it "should..." do
AwesomeGem.something = false
# ...
AwesomeGem.something = true
end
This is stupid and short-sighted. Next week, someone changes the default value, and everything breaks. What you need to do is capture the value before you change it, then return it to that state at the end of the test:
it "should..." do
old_value = AwesomeGem.something
AwesomeGem.something = false
# ...
AwesomeGem.something = old_value
end
This works, but it’s shit code, especially if you’re repeating it in dozens of specs. You can DRY it up a bit by moving it to before and after blocks, but it’s a heap of noisy, ugly code. We can do better. How about wrapping the above pattern up in a block that temporarily changes the configuration, like this:
it "should..." do
with_config :something, false do
# ...
end
end
Here’s the implementation, throw it in your spec_helper.rb file:
def with_config(preference_name, temporary_value, &block)
old_value = AwesomeGem.send(preference_name)
AwesomeGem.send(:"#{preference_name}=", temporary_value)
yield
AwesomeGem.send(:"#{preference_name}=", old_value)
end
Enjoy!
Before you go…
Here’s some links to my most popular posts: