Question

Is it possible (and reasonable) to write Controller tests and classes before writing the underlying Model classes? I thought I saw notes on how to do that, but now I can't find the recipe.

For example, consider the following controller:

# file: app/controllers/premises_controller.rb
class PremisesController < ApplicationController

  def create
    @premise = Premise.new(params[:premise])
    respond_with @premise
  end

end

Can I test this controller code before creating the underlying Premise model and premises? I know the following won't work -- how would you re-write it (if it's possible)?

# file: spec/controller/premise_spec.rb
require "spec_helper.rb"

describe PremisesController do
  context 'POST create' do
      it 'should assign a new Premise to @premise' do
        premise = stub_model(Premise)
        Premise.stub(:create) { premise }
        post :create
        assigns(:premise).should == premise
      end
    end
  end
end

update

The more I think about it, the more I'm convinced that I do need to define the Premise class -- the PremisesController code needs to reference it. So I'll change my question to "is it necessary to create the underlying premises database table in order to run the PremisesController tests?"

At this point, I don't see a good way around it (without changing the PremisesController code, which defeats the point of testing). For example, the call to respond_with calls @premise.has_errors? which in turn accesses the database to fetch the column names. Unless I'm willing to stub methods internal to ActiveRecord, I don't see how to avoid a hit to the DB.

But I'd love to be shown otherwise.

Was it helpful?

Solution 2

Okay - I've made my peace with this: it's not practical to create any meaningful tests unless the database table exists -- too many bits of ActiveRecord depend on having the table defined.

But this doesn't prevent writing test that with a clean separation between the controller and the model. This is eloquently covered by dchelimsky Himself in this RSpec issue. The gist of his post:

  • Test using an integration test in spec/requests/premise_spec.rb which issues a get and verifies the generated json response.
  • With a skinny controller method (such as shown in the OP), don't bother writing a controller test.
  • Write model tests to verify that the model is emitting the correct json.

By the way, I really recommend reading David's post -- he takes you through a step-by-step process, explaining the philosophy and the reasoning behind each step.

OTHER TIPS

I haven't tested this code yet, but pretty sure it should work. You could do this for now: Just a start, but you could try something like this if you want to, though it is probably bad practice to change your code like this just to pass specs.

class PremisesController < ApplicationController
  def create
    @premise = premise_until_model_finished params[:premise]
    respond_with @premise
  end

  def premise_until_model_finished premise
    Premise.new premise
  end
end


require "spec_helper.rb"

describe PremisesController do
  context 'when creating a premise' do
    before :each do        
      @my_fake_model = { 
        :some_attribute => 'funk', 
        :some_other_attribute => 'a-delic'
      }
      PremisesController.any_instance.stub( :premise_until_model_finished).and_return(
        @my_fake_model 
      )
      PremisesController.any_instance.should_receive( 
        :premise_until_model_finished
      ).and_return( @my_fake_model )
      post :create
    end

    it 'should create a premise as expected' do
      # your criteria here...
    end
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top