【问题标题】:Simple rspec question简单的 rspec 问题
【发布时间】:2011-06-22 20:02:54
【问题描述】:

我真的在努力学习 rspec :( 所以我希望你能在控制器中通过一个非常简单的 create-action 给我一点帮助。我想为此使用 Rspec::mocks,因为我认为这是这样做的方法吗?而不必在测试时访问数据库。

我有一个 before_filter:

def find_project
   @project= Project.find_by_id(params[:project_id])
end

创建操作如下所示:

def create
  @batch = Batch.new(params[:batch])
  @batch.project = @project

  if params[:tasks]
    params[:tasks][:task_ids].each do |task_id|
      @batch.tasks << Task.find(task_id)
    end
  end

  if @batch.save
    flash[:notice] = "Batch created successfully"
    redirect_to project_batch_url(@project, @batch)
  else
    render :new
  end
end

对于@batch.project = @project,我真的很怀疑我如何定义@project?还有整个params[:tasks][:task_ids].each 部分.. 是的.. 几乎整个事情:(

抱歉这个新手问题 - 希望你们能帮助或至少指出我正确的方向:)

谢谢

【问题讨论】:

  • Jesper:我觉得你的问题有点难以理解。你到底有什么困难?您能否改写一下以添加说明?

标签: ruby-on-rails testing controller rspec


【解决方案1】:

控制器规范的想法是检查操作是否正在设置实例变量,并根据需要进行重定向/渲染。要设置规范,您通常会创建一个对象或模拟,设置属性/存根,然后调用该操作,并在必要时传递参数哈希。

例如(航空代码)

describe MyController do
  before(:each) do
    @project = mock_model(Project)
    Project.stub(:find_by_id) {@project}
    @batch = mock_model(Batch)
    Batch.stub(:new) {@batch}
  end

  it "should redirect to project_batch_url on success" do
    @batch.stub(:save) {true)
    post :create, :batch => { :some_key => :some_value }, :tasks => { :task_ids => [1,2,3] }
    response.should redirect_to(project_batch_url(@project,@batch))
  end

  it "should render :new on failure" do
    @batch.stub(:save) {false)
    post :create, :batch => { :some_key => :some_value }, :tasks => { :task_ids => [1,2,3] }
    response.should render_template("new")
  end
end

您可以在RSpec Rails docs 中找到更多相关信息。

【讨论】:

    【解决方案2】:

    使用 BDD 可帮助您定义接口。因此,如果您的控制器希望项目创建一个批处理并添加一些任务 ID,那么“编写您希望拥有的代码”。在控制器的实践中,这意味着试图将逻辑从控制器中推出到你的模型中。测试模型往往更直观,而且肯定比测试控制器更快。

    从“mockist”的角度来看,这里有一些可能的规格(未经测试):

    # controller spec  
    describe BatchesController do
      def mock_project(stubs={})
        @mock_project ||= mock_model(Project, stubs)
      end
    
      def mock_batch(stubs={})
        @mock_batch ||= mock_model(Batch, stubs)
      end
    
      context "POST create"
        it "calls #create_batch_and_add_tasks on the project"
          mock_project.should_receive(:create_batch_and_add_tasks).with(
            :batch => { :name => 'FooBatch' },
            :task_ids => [1,2,3,4]
          )
          Project.stub(:find).and_return(mock_project)
    
          post :create, :batch => { :name => 'FooBatch' }, :tasks => { :task_ids => [1,2,3,4] }
          # consider changing your params to :batch => { :name => 'FooBatch', :task_ids => [1,2,3,4] }
        end
    
        it "redirects to the project_batch_url on success" do
          mock_project(:create_batch_and_add_tasks => mock_batch(:save => true))
          Project.stub(:find) { mock_project }
          post :create, :these_params => "don't matter because you've stubbed out the methods"
        end
    
    # controller
    def create
      @batch = @project.create_batch_and_add_tasks(
                 :batch => params[:batch],
                 :task_ids => params[:tasks].try([:tasks_ids])
               )
      if @batch.save
        ...
    

    【讨论】:

    • monocle:感谢您的回答 :) 感谢您帮助我保持我的控制器瘦! :) 使用 rspec 进行控制器测试是正确的方法吗?或者您对此有何看法?
    • 我认为没有“正确”的方式。当您习惯了 RSpec 时,您会发现自己喜欢如何测试事物。查看 RSpec Book 了解更多信息。
    猜你喜欢
    • 2011-10-31
    • 2011-01-29
    • 2018-03-07
    • 2011-10-30
    • 2013-02-17
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多