[MEGOLDVA] Rails3 rspec lambda {}.should change() wtf

Rails v3.0.3 Rspec 2.4.0

Van a User model, es - az ugy szempontjabol mindegy miert - a kontroller update-je vedi meg a .login mass_update-tol, azaz a modelben attr_accessible :login.
A vedelmet a kontrollerbol kiszedtem, hogy az rspec teszten latszodjon hogy mukodik e.

Alapvetoen ez tunik elegans - olvashato tesztnek:


  before :each do
    @me = Factory :user
    controller.stub(:current_user).and_return(@me)
  end 

  describe "update" do

    it "should protect against changing login" do  
      lambda {
        put :update, :id => @me.id, :user => { :login => Factory.next(:login) }
      }.should_not change(User.find(@me), :login)
    end
  end

csakhogy sajnos ez nem azt teszteli amit szeretnek, ui 1/1 passing.

ez viszont mukodik:


    it "should protect against changing login" do
      login = @me.login
      put :update, :id => @me.id, :user => { :login => Factory.next(:login) }
      @me = User.find(@me)
      @me.login.should == login 
    end 

azt adja hogy


  1) UsersController update should protect against changing login
     Failure/Error: @me.login.should == login
       expected: "user_1"
            got: "user_2" (using ==)
     # ./spec/controllers/users_controller_spec.rb:16:in `block (3 levels) in <top (required)>'

Ha az elsot letagadom hogy latszodjek mit tesztel:


  2) UsersController update should protect against changing login 2
     Failure/Error: lambda {
       login should have changed, but is still "user_3"
     # ./spec/controllers/users_controller_spec.rb:20:in `block (3 levels) in <top (required)>'

Kerdes: mert nem mukodik (hibasan megy at rajta a kontroller) az elso teszt?

Hozzászólások

nemi debuggolas utan a megoldas:

az rspec melyen a change modulban a kerdeses objektum


  def initialize(receiver=nil, message=nil, &block)
     @value_proc = block || lambda {receiver.__send__(message)}

kent ertekelodik ki a lambda elott es utan ahol a receiver a User.find(@me), es message a :login.

Csakhogy a receiver objektum egyszer, inicializacio kozben beallitodik, es anak mindegy hanyszor kuldjuk el a login-t, abban a peldanyban sosem valtozik.

Block-kal ugyanez a teszt mar mukodik:


 19     it "should protect against changing login 2" do
 20       lambda {
 21         put :update, :id => @me.id, :user => { :login => Factory.next(:login) }
 22       }.should_not (change { User.find(@me).login })