model_stubbing for the common man (or woman)
UPDATE: Fixed a few errors that Rick pointed out. Oops!
So, I wrote a while ago about model_stubbing and why it was my favorite way to replace fixtures. A few people wrote me asking questions about model_stubbing, so I figured I’d write up a tutorial (notwithstanding the fact that I said “I’m writing a tutorial on model_stubbing” in the last post…).
Philosophy
The model_stubbing plugin lets you do just that: stub models. You can setup model stubs that contain data that you specify. Of course, there are already a lot of solutions out there for this problem (one of them built into Rails actually), but model_stubbing differs from these other solutions in this area in three primary ways.
First, it creates real instances of model objects (unlike most stub libs). Creating real instances means that it goes through all your lifecycle methods, callbacks, etc. rather than simply stubbing out the readers on fake objects. This approach gives you the advantage of being able to test your code in a “real” object ecosystem and do effective functional/integration testing with your models with stubbed data.
Second, it lets you have multiple stubs for the same model and use them naturally (unlike most factories). This is where model_stubbing really exploits the good parts of the factory approach and the fixture approach. You get real objects while being able to address them with something as simple as users(:jeremy) (I’ll show you how this works in just a bit…).
Third, it uses straight Ruby, so it’s easy to add your own logic or wrap helpers into it (unlike fixtures). You can easily write macros to do things like easily stub an STI table (e.g., rather than stubbing a User model and filling in type, permissions, etc. etc., you could simply make a moderator_stub method or some such to generate all that for you).
Getting model_stubbing
You can grab model_stubbing from Rick’s Github here: http://github.com/technoweenie/model_stubbing/tree/master
Specifying models and stubs
Here’s a very basic model stub:
# RSpec describe block...works in other testing tools, too!
describe "A fancy controller" do
define_models do
model Site do
stub :title => “My Company”, :private => false
end
end
it “should do something magical…” do
# blah blah blah
end
end
You use the define_models method right inside your testing context (describe blocks if you’re on RSpec). You’ll notice that there are three primary methods in use here: define_models, model, and stub. The define_models method basically says, “Hey, I’m going to be shoving stubs in this block. kthxbai.” It does a little more than that, but I’ll discuss exactly what later on.
Next, the model method lets you specify which model class you’re going to be generating stubs for. So, in this example, we’re generating stubs for our Site model class. You can sub any class in there, but it can only be one class at a time.
Finally, we drill down to the stub method, which actually creates a stub. In this case, we’re making a default stub for the Site class with the title “My Company” and the private attribute set to false. Now you can address this stub in code by doing sites(:default). You can create subsequent stubs like so…
define_models do
model Site do
stub :title => "My Company", :private => false
stub :entp, :title => "entp Company HQ", :private => false
stub :caboose, :title => "Caboo.se", :private => true
end
end
And address by the name you give them as the first argument (in this case, something like sites(:entp) or sites(:caboose)).
Inheriting stubs
One of the great time saving features of model_stubbing is that it lets you inherit attributes from previous stubs. So, for example, if we have a set of stubs for blogs like this:
define_models do
model Blog do
stub :name => "OMGBLOGLOL!!", :rss => true, :atom => true, :html => true, :scrape => true
stub :fireball, :name => "Daring Fireball", :rss => true, :atom => true, :html => true, :scrape => true
stub :techcrunch, :name => "TechCrunch", :rss => true, :atom => false, :html => true, :scrape => true
stub :hoth, :name => "entp Hoth", :rss => true, :atom => false, :html => true, :scrape => true
end
end
We could refactor them to be much shorter like so:
define_models do
model Blog do
stub :name => "OMGBLOGLOL!!", :rss => true, :atom => true, :html => true, :scrape => true
stub :fireball, :name => "Daring Fireball"
stub :techcrunch, :name => "TechCrunch", :atom => false
stub :hoth, :name => "entp Hoth"
end
end
The stubs inherit their attributes from the stubs above them. So blogs(:fireball) has the same attributes as the :default stub unless it changes something (e.g., its name in this case), and any subsequent stub will have those same attributes unless one is changed (as we did with the :techcrunch stub’s :atom attribute, which will then pass its changed attributes down to subsequent stubs). So, in this case, the :fireball blog has the same attribtues as :default with the exception of name.
Associations and other stuff
model_stubbing. You simply refer to a stub on the belongs_to side of an association (since that’s the side that the association_id has to be filled in on). So, for example, if we had a stub for Authors that belong to our above Blog models, we could do something like this:define_models do
model Author do
stub :name => "Jeremy", :blog => blogs(:default)
stub :gruber, :name => "John", :blog => blogs(:fireball)
end
end
You simply refer to them as you would in normal testing code (previously there was an all_stubs method, but that’s gone now!).
Breaking stubs up
So far I’ve only shown you how to embed the stubs in a describe block, but you can also split them out into their own file and require it into your specs or spec helper. At that point you simply need to call define_models to get your stubs in place.
describe "A fancy controller" do
define_models
it "should do something magical..." do
# blah blah blah
end
end
This call will load all the default stubs. I say “default” because you can also namespace your stubs to an extent. So, if you need different stubs for different contexts (very useful for only loading the stubs you need to test a certain portion of a system), then you can change your define_models call slightly.
ModelStubbing.define_models :permissions do
model User do
stub :name => "Jeremy", :login => "jeremy", :password => "merph"
end
model Permission do
stub :object => 'Blog', :permission => 'edit', :user => user(:default)
end
end
Using this form, you can name a set of stubs, giving them a label you can refer to later. Then you can change your define_models call in your specs to something like:
describe "Your protected controller" do
define_models :permissions
it "should keep out the hoi polloi." do
# blah blah blah
end
end
Stupid stubbing tricks!
The final section of this post is just a grab bag of random techniques I’ve picked up from working with model_stubbing.
Generating random data for stubs
The cool thing about this using Ruby is that you can use other Ruby code with it, like the Faker gem from Ben Curtis. Using Faker, you can generate random stubs easily:
ModelStubbing.define_models do
model User do
stub :name => Faker::Name.name, :email => Faker::Internet.email, :admin => false
stub :admin, :admin => true
end
end
You can find out more about the Faker gem over at the docs here.
(OK, really it’s just one trick but I’ll more here later…I promise! :))








