从模型中隔离控制器测试

时间:2012-03-31 01:46:57

标签: ruby-on-rails-3 mocking rspec2 stubbing

在编写底层Model类之前编写Controller测试和类是否可能(也是合理的)?我以为我看到了如何做到这一点的笔记,但现在我找不到食谱了。

例如,请考虑以下控制器:

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

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

end

我可以在创建基础Premise模型和前提之前测试此控制器代码吗?我知道以下内容不起作用 - 你会如何重写它(如果可能的话)?

# 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

更新

我越是想到它,我越相信我需要定义Premise类 - PremisesController代码需要引用它。所以我将我的问题改为“是否有必要创建基础premises数据库表以运行PremisesController测试?”

此时,我看不到一个好方法(不改变PremisesController代码,这会破坏测试点)。例如,对respond_with的调用调用@premise.has_errors?,后者又访问数据库以获取列名。除非我愿意将ActiveRecord内部的方法存根,否则我不会看到如何避免对数据库的命中。

但是我很乐意以其他方式表现出来。

2 个答案:

答案 0 :(得分:0)

我还没有测试过这段代码,但很确定它应该可行。你现在可以这样做: 只是一个开始,但如果你愿意,你可以尝试这样的事情,虽然改变你的代码可能是不好的做法只是为了传递规格。

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

答案 1 :(得分:0)

好的 - 我已经平静下来了:除非数据库表存在,否则创建任何有意义的测试都是不切实际的 - ActiveRecord的太多位依赖于定义表。

但这并不妨碍在控制器和模型之间进行清晰分离的编写测试。 dchelimsky自己在this RSpec issue中雄辩地阐述了这一点。他的帖子的主旨是:

  • 使用spec / requests / premise_spec.rb中的集成测试进行测试,该测试发出get并验证生成的json响应。
  • 使用瘦的控制器方法(如OP中所示),不要打扰编写控制器测试。
  • 编写模型测试以验证模型是否正在发出正确的json。

顺便说一句,我真的建议阅读David的帖子 - 他会带你逐步完成一个步骤,解释每一步背后的理念和推理。