Controller Specs / Edits

9 days ago

Edited line 15 :

Note: not everyone agrees this is a good idea. But it’s good to know about this approach and why some people like it.

Matchers.

Merb core provides number of matchers for RSpec:

  • redirect
  • redirect_to (aliased as be_redirection_to)
  • be_success (aliased as respond_successfully)
  • be_missing (aliased as be_client_error)

redirect_to takes :message option in case your action uses redirect with it.

10 days ago

Edited line 87 :

Article.stub!(:with_slug).with("slug").and_return @article
Article.stub(:with_slug).with("slug").and_return @article

2 months ago

Edited line 38 :

it "fetches all articles in descending order of date created" do
it "should get all articles in descending order of date created" do

Edited line 50 :

This will make sure the index action will always display the articles in descending order without actually querying the database or rendering the view, meaning you don’t have to worry about populating the database from fixtures or rendering errors. It is not always the case so you can use fixtures and do not stub display so you can operate on response body to do some assertions.

This will make sure the index action will always display the articles in descending order without actually querying the database or rendering the view, meaning you don’t have to worry about populating the database from fixtures or rendering errors.

Edited line 65 :

begin @article = Article.with_slug(id) display @article rescue YourOrm::RecordNotFoundOrSomething raise NotFound end
@article = Article.with_slug(id) raise NotFound unless @article display @article

Edited line 72 :

And the spec for an action with a parameter (if you really feel you have to stub display):

And the spec for an action with a parameter:

Edited line 95 :

Notice that the request path and method are not specified anywhere. Merb dispatch_to helper allows you to invoke an action without specifying the request method, keeping your routes removed from your controller tests. If you want to spec your routes (and you always do), Merb provides helpers & matchers specifically for testing your routes. See the [Routing Specs] for more. If your action’s behavior depends on the request method, the get, post, put, delete will allow you to fake the request method and NOT bypassing routing.

Notice that the request path and method are not specified anywhere. Merb allows you to invoke an action without specifying the request method, keeping your routes removed from your controller tests. If you want to spec your routes (and you always do), Merb provides helpers & matchers specifically for testing your routes. See the Routing Specs for more.

If your action’s behavior depends on the request method, the get, post, put, delete will allow you to fake the request method.

4 months ago

Edited line 39 :

it "should get all articles in descending order of date created" do
it "should get all articles in descending order of :date created" do

4 months ago

Edited line 39 :

it "should get all articles in descending order of :date created" do
it "should get all articles in descending order of date created" do

4 months ago

Edited line 22 :

 
 

Edited line 34 :

 
 

Edited line 56 :

 
 

Edited line 75 :

 
 

Edited line 113 :

 
 

4 months ago

Edited line 114 :

describe "requesting /pages with GET" do before(:each) do Page.stub!(:all).and_return(pages) end
describe "requesting /pages with GET" do before(:each) do Page.stub!(:all).and_return(pages) end

Edited line 119 :

def do_get dispatch_to(Pages, :index) do |controller| controller.stub!(:display)
def do_get dispatch_to(Pages, :index) do |controller| controller.stub!(:display) end

Edited line 123 :

end

Edited line 125 :

it "should be successful" do do_get.should be_successful end
it "should be successful" do do_get.should be_successful end

Edited line 129 :

it "should load all page records" do Page.should_receive(:all).and_return(pages) do_get.assigns(:pages).should == pages # pages is defined elsewhere end
it "should load all page records" do Page.should_receive(:all).and_return(pages) do_get.assigns(:pages).should == pages # pages is defined elsewhere end

Edited line 134 :

it "should display all pages" do dispatch_to(Pages, :index) do |controller| controller.should_receive(:display).with(pages) # pages is defined elsewhere
it "should display all pages" do dispatch_to(Pages, :index) do |controller| controller.should_receive(:display).with(pages) # pages is defined elsewhere end

Edited line 139 :

end

4 months ago

Edited line 42 :

dispatch_to(Articles, :index) do |controller|
dispatch_to(Article, :index) do |controller|

4 months ago

Edited line 19 :

Lets say we have an Articles controller with an index we want to spec:

 
class Articles < Application 
Lets say we have an Articles controller with an index we want to spec:
class Articles < Application 

Edited line 26 :

We could spec this index action to make sure it always fetches the articles from the database in descending order by date:
describe Articles do 

Edited line 29 :

We could spec this index action to make sure it always fetches the articles from the database in descending order by date:

 
describe Articles do 
 

Edited line 41 :

This will make sure the index action will always display the articles in descending order without actually querying the database or rendering the view, meaning you don’t have to worry about populating the database from fixtures or rendering errors.

Edited line 44 :

This will make sure the index action will always display the articles in descending order without actually querying the database or rendering the view, meaning you don’t have to worry about populating the database from fixtures or rendering errors.

Lets add a show action with an id parameter:
class Articles < Application 

Edited line 46 :

Lets add a show action with an id parameter:

 
class Articles < Application 
 

Edited line 58 :

And the spec for an action with a parameter:
describe Articles do 

Edited line 61 :

And the spec for an action with a parameter:

 
describe Articles do 
 

Edited line 77 :

Notice that the request path and method are not specified anywhere. Merb allows you to invoke an action without specifying the request method, keeping your routes removed from your controller tests. If you want to spec your routes (and you always do), Merb provides helpers & matchers specifically for testing your routes. See the Routing Specs for more.

Edited line 79 :

Notice that the request path and method are not specified anywhere. Merb allows you to invoke an action without specifying the request method, keeping your routes removed from your controller tests. If you want to spec your routes (and you always do), Merb provides helpers & matchers specifically for testing your routes. See the Routing Specs for more.

Edited line 80 :

Taming Spec Complexity

Sometimes your specs can grow quite complex. It’s often handy to abstract away some complexity. Here are some tips for handling complexity with abstraction.

Handling Requests

Did you notice in the above examples the frequent usage of dispatch_to? It’s sometimes best to wrap up the test request to your controller so that each example in your spec is making the same sort of request. For example:

 
  describe "requesting /pages with GET" do 
    before(:each) do 
      Page.stub!(:all).and_return(pages) 
    end 
 
    def do_get 
      dispatch_to(Pages, :index) do |controller| 
        controller.stub!(:display) 
      end 
    end 
 
    it "should be successful" do 
      do_get.should be_successful 
    end 
 
    it "should load all page records" do 
      Page.should_receive(:all).and_return(pages) 
      do_get.assigns(:pages).should == pages # pages is defined elsewhere 
    end 
 
    it "should display all pages" do 
      dispatch_to(Pages, :index) do |controller| 
        controller.should_receive(:display).with(pages) # pages is defined elsewhere 
      end 
    end 
  end 

The method do_get neatly summarizes the most common request we’re making in our spec, handles any stubs, and has a wonderfully descriptive name to describe what’s happening.

Notice in the last example in the above spec that we don’t have to use do_get. In this last example we hand write our usage of dispatch_to to ensure that a particular method is being called.

4 months ago

Edited line 28 :

describe Articles do 
 
describe Articles do 

Edited line 46 :

class Articles < Application 
 
class Articles < Application 

Edited line 62 :

describe Articles do 
 
describe Articles do 

4 months ago

Edited line 20 :

class Articles < Application 
 
 
class Articles < Application 

Edited line 28 :

Edited line 32 :

Edited line 46 :

Edited line 52 :

Edited line 66 :

Edited line 70 :

Edited line 88 :

4 months ago

4 months ago

Edited line 22 :

class Articles < Application def index @articles = Article.all(:order => 'created_at desc') display @articles
class Articles < Application def index @articles = Article.all(:order => 'created_at desc') display @articles end

Edited line 27 :

end

Edited line 33 :

describe Articles do
describe Articles do

Edited line 35 :

describe "#index" do
describe "#index" do

Edited line 37 :

it "should get all articles in descending order of date created" do Article.should_receive(:all).with(:order => 'created_at desc')
it "should get all articles in descending order of date created" do Article.should_receive(:all).with(:order => 'created_at desc')

Edited line 40 :

dispatch_to(Article, :index) do |controller| controller.stub!(:display)
dispatch_to(Article, :index) do |controller| controller.stub!(:display) end

Edited line 45 :

end

Edited line 71 :

describe Articles do
describe Articles do

Edited line 73 :

describe "#show" do
describe "#show" do

Edited line 75 :

before(:each) do @article = mock(:article) end
before(:each) do @article = mock(:article) end

Edited line 79 :

it "should display the article matching the slug id" do Article.stub(:with_slug).with("slug").and_return @article
it "should display the article matching the slug id" do Article.stub(:with_slug).with("slug").and_return @article

Edited line 82 :

dispatch_to(Articles, :show, :id => "slug") do |controller| controller.should_receive(:display).with(@article)
dispatch_to(Articles, :show, :id => "slug") do |controller| controller.should_receive(:display).with(@article) end

Edited line 87 :

end

Edited line 89 :

Notice that the request path and method are not specified anywhere. Merb allows you to invoke an action without specifying the request method, keeping your routes removed from your controller tests. If you want to spec your routes (and you always do), Merb provides helpers & matchers specifically for testing your routes. See the Routing Specs for more.

If your action’s behavior depends on the request method, the get, post, put, delete will allow you to fake the request method.

4 months ago

4 months ago

4 months ago

Edited line 48 :

Lets add a show action with an id parameter:
 
 
class Articles < Application 
 
  def index 
    @articles = Article.all(:order => 'created_at desc') 
    display @articles 
  end 
 
  def show(id) 
    @article = Article.with_slug(id) 
    raise NotFound unless @article 
    display @article 
  end 
end 
 
And the spec for an action with a parameter:
 
 
  describe Articles do 
 
    describe "#show" do 
 
      before(:each) do 
        @article = mock(:article) 
      end 
 
      it "should display the article matching the slug id" do 
        Article.stub(:with_slug).with("slug").and_return @article 
 
        dispatch_to(Articles, :show, :id => "slug") do |controller| 
          controller.should_receive(:display).with(@article) 
        end 
      end 
    end 
  end 
 

4 months ago

Edited line 19 :

Lets say we have an Articles controller with an index we want to spec:

Lets say we have an Articles controller with an index we want to spec:

Edited line 32 :

We could spec this index action to make sure it always fetches the articles from the database in descending order by date:

We could spec this index action to make sure it always fetches the articles from the database in descending order by date:

Edited line 45 :

dispatch_to(Article, :index) do |controller| controller.stub!(:display) end
dispatch_to(Article, :index)

Edited line 50 :

This will make sure the index action will always display the articles in descending order without actually querying the database or rendering the view, meaning you don’t have to worry about populating the database from fixtures or rendering errors.

4 months ago

Edited line 13 :

It is also a good idea to stub the render and display methods for your controller. These methods invoke the view, which should be left to the view specs.

Examples

Lets say we have an Articles controller with an index we want to spec:

 
 
  class Articles < Application 
    def index 
      @articles = Article.all(:order => 'created_at desc') 
      display @articles 
    end 
  end 
 

We could spec this index action to make sure it always fetches the articles from the database in descending order by date:

 
 
  describe Articles do 
 
    describe "#index" do 
 
      it "should get all articles in descending order of date created" do 
        Article.should_receive(:all).with(:order => 'created_at desc') 
 
        dispatch_to(Article, :index) 
      end 
    end 
  end 
 

Examples

4 months ago

Edited line 4 :

Keep In Mind

Controller specs work best when the interaction with models have been completely stubbed out. Checkout the RSpec documentation for more info on how to stub & mock for your models.

Examples

4 months ago