Isolated controller and view testing in merb 2

Posted by Tim Connor Mon, 17 Dec 2007 08:41:00 GMT

As part of learning rspec for blerb, I’m working on better mocking for truer isolation tests. This includes true unit tests for models, controllers, and views, unlike the rails/testunit standard approach. This involves, primarily, mocking out the models and turning rendering off for the controller testing, and figuring out how to test just the rendering without the rest of the stack, for the views. I won’t claim any of this is well organized, or finalized, as we are just figuring out how to do some of it in the first place, but feel free to crib any of this you like off the git-web for blerb.

First a controller

describe “Articles Controller”, “index action” do
before(:each) do
article1 = mock("article") @article2 = mock("article") @articles = [article1, article2] Article.should_receive(:all).and_return(articles)
@controller =

it “should get successfully” do @controller.status.should == 200 end it “should assign all articles” do controller.instance_variable_get("articles").should == @articles end


The one non-intuitive part (for me), was making sure to stub render – otherwise you’ll be calling the view, and getting errors on your mocks because the view is calling methods you didn’t mock/stub out. Thus, it is key to isolate the controller from the model and the view if you want to easily test it, in this style. Oh yeah, and knowing about fake_request as part of the merb testing help.

The slightly trickier part was doing the same for the views. I dug through the merb source, and got most of the way, but hadn’t figured out how to pass in assigned instance variables by creating a dummy ViewContext, when ezra gave me a hand. I would NOT (and will not long term) do it exactly like this, but rather extract some sort of spec_helper to wrap the fake view_context creation and template engine calls, but it’s useful as is for an illustrative example.

class FakeArticleController
  def initialize(articles)
    @articles = articles

describe "/articles" do
  before(:each) do
    @article1 = mock("article")
    @article2 = mock("article")
    @article1.should_receive(:title).and_return("Article 1")
    @article2.should_receive(:title).and_return("Article 2")    

    @template = "#{MERB_VIEW_ROOT}/articles/index.html.erb"
    @engine = Merb::Template.engine_for(@template)
    @fake =
    @body = @engine.transform(:file => @template, :view_context => @fake)
  it "should list all articles" do
    @body.should include("<li>Article 1</li>")
    @body.should include("<li>Article 2</li>")