0

我有一个令人困惑的 rSpec 问题 - 取决于我编写代码的方式,描述“失败”规范的测试失败或描述“成功”规范的测试失败。

以下是创建操作的测试:

describe "POST 'create'" do

  describe "failure" do

    before(:each) do
      @attr = {name: "", type_of_group: ""}
      @student_attr = [{name: "Joe", gender: "Male"}, {name: "sally twotrees", gender: "Female"}]
      @create = post :create, student_group: @attr, student: @student_attr
    end

    it "should have the right title" do
      @create
      response.should have_selector('title', :content => "Create a new group" )
    end

    it "should render the 'new' page" do
      @create
      response.should render_template('new')
    end

    it "should not create a user" do
      lambda do
        post :create, student_group: @attr
      end.should_not change {@user.student_groups.count}
    end

    it "should flash an error message" do
      @create
      flash[:error].should =~ /please/i
    end

  end

  describe "success" do

    before(:each) do
      @attr = FactoryGirl.attributes_for(:student_group)
      # @student_attr = {name: "test", gender: "Male"}
    end     

    it "should create a student_group" do  
      lambda do
        post :create, student_group: @attr
      end.should change {@user.student_groups.count}.by(1)
    end

    it "should create students" # do
      # lambda do
      #   post :create, student_group: @attr, student: @student_attr
      #   end.should change {@student_groups.students.count}.by(1)  
      # end  

    it "should flash a success message" do
      post :create, student_group: @attr
      flash[:success].should =~ /has been added/i
    end

    it "should redirect" do
      post :create, student_group_id: @group, student_group: @attr
      response.should be_redirect
    end

  end 

end

所有“失败”测试都因以下错误而失败:

Failure/Error: @create = post :create, student_group: @attr, student: @student_attr
 ActionView::Template::Error:
   `@student_group[students_attributes]' is not allowed as an instance variable name

如果我以这种方式在控制器中编写代码:

def create
  @params = params[:student_group][:students_attributes]
  @student_group = @user.student_groups.build(params[:student_group])

  if @student_group.save
    ###   RE: 'defensive coding' https://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array  
    if @params.present?
      ### https://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
      @params.each do |student|
        @student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
      end
    end 
    # new subject path
    redirect_to class_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully" }   
  else
    @title = "Create a new group"
    flash.now[:error] = "Something's gone wrong.  Please try again!"
    render 'new' 
  end  
end

如果控制器代码是这样编写的,那么所有的“成功”测试都会失败:

def create
  @params = params[:student_group][:students_attributes]
  @student_group = @user.student_groups.build(params[:student_group])
  ### http://railsforum.com/viewtopic.php?pid=40056#p40056
  if @params.present?
    @student = Student.new
  else 
    @student = @student_group.students.build(@params)
  end 
  if @student_group.save
    ###   RE: 'defensive coding' https://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array  
    if @params.present?
      ### https://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
      @params.each do |student|
        @student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
      end
    end 
    # new subject path
    redirect_to class_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully" }   
  else
    @title = "Create a new group"
    flash.now[:error] = "Something's gone wrong.  Please try again!"
    render 'new' 
  end  
end   

表单代码在这里:https ://stackoverflow.com/a/17591802/2128691

4

2 回答 2

0

我最终使用了这段代码:

def create
  @student_group = @user.student_groups.new(params[:student_group]) 
  @params = params[:student_group][:students_attributes]
  @student_group = @user.student_groups.build(params[:student_group])
  if @student_group.save
    ###   RE: 'defensive coding' http://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array  
    if @params.present?
      ### http://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
      @params.each do |student|
        @student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
      end
    end 
    redirect_to new_student_group_subject_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully.  Next, add the subjects for this group" }   
  else
    ### http://railsforum.com/viewtopic.php?pid=40056#p40056  
    @student = @student_group.students.build
    @title = "Create a new group"
    flash.now[:error] = "Something's gone wrong.  Please try again!"
    render 'new' 
  end  
end
于 2013-08-07T08:12:55.133 回答
0

从上面的代码看来,您的控制器代码确实搞砸了。在嵌套属性的情况下,您只需保存父对象。如果子对象有效,它们会自动保存。您也不需要为某些实例对象分配参数。它们应该直接使用。嵌套属性的一个简单示例可以是

User
  has_many :comments
  accepts_nested_attributes_for :comments

Comment
  belongs_to :user

你的控制器代码应该是

def create
  @user = User.new(params[:user]) 
  if @user.save
    flash[:notice] = 'success'
    redirect_to some_path and return
  end
  render 'new'
end

rspec 控制器测试用例可以是

it "should create a user with comments if valid data is provided" do
  post :create, "user"=>{"name"=>"Prasad", "comments_attributes"=>{"0"=>{"comment"=>"first comment"}, "1"=>{"comment"=>"second comment"}}, "commit"=>"Save"
  user = assigns[:user] #assigns lets u access the instance variable from the controller in the spec
  user.should be_valid
  user.comments.count.should == 2 #check that all the child models are saved
  user.name.should == "Prasad"
  user.comments.first.comment.should == 'first comment'
  user.comments.last.comment.should == 'second comment'
  response.should be_redirect(some_path) #since u redirected in the code 
end

说真的,你需要通过rails guides。

于 2013-07-12T12:54:14.713 回答