Csongor Bartus
2008-Jun-20 15:12 UTC
[rspec-users] before_save model callback rspec testing
hi all, i''m learning rspec and i can''t figure out how to test if a callback is executed in a model. my model code is: class User < ActiveRecord::Base before_save :encrypt_password ... def encrypt(password) self.class.encrypt(password, salt) end thanks a lot, cs. -- Posted via http://www.ruby-forum.com/.
user.should_receive(:encrypt_password).with(your_password) user.save Is this what you want? On Fri, Jun 20, 2008 at 10:12 AM, Csongor Bartus <lists at ruby-forum.com> wrote:> hi all, > > i''m learning rspec and i can''t figure out how to test if a callback is > executed in a model. > > my model code is: > > class User < ActiveRecord::Base > before_save :encrypt_password > > ... > > def encrypt(password) > self.class.encrypt(password, salt) > end > > > thanks a lot, > cs. > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-20 15:23 UTC
[rspec-users] before_save model callback rspec testing
It might be .... I''ve done this : it "should encrypt password before save" do user = mock("User") user.should_receive(:encrypt_password).with("password") user.save end but I''ve got : Spec::Mocks::MockExpectationError in ''User ActiveRecord Callbacks before save encrypt password'' Mock ''User'' received unexpected message :save with (no args) ./spec/models/user_spec.rb:84: -- Posted via http://www.ruby-forum.com/.
Hey, This isn''t doing much to test the *behavior* of the object. Why do you want to encrypt the password? Probably so you can authenticate, right? I would probably start off with describe "authenticate" do it "finds the user with the given credentials" do u = User.create!(:login => "pat", :password => "password") User.authenticate("pat", "password").should == u end end That might be a bit much to chew at first though. So you can write some interim tests that you then throw away. For example, you might do describe User, "when saved" do it "should create a salt" do u = User.create(:login => "pat", :password => "password") u.salt.should_not be_blank end it "should create a hashed pass" do u = User.create(:login => "pat", :password => "password") u.hashed_pass.should_not be_blank end end Once you have those passing, you can move to the User.authenticate spec. Once *that* passes, you can throw away the salt/hashed_pass specs, because they''re no longer useful. They''re testing implementation at this point, and were just a tool to get you where you wanted to go in small steps. Pat On Fri, Jun 20, 2008 at 8:15 AM, Yi Wen <hayafirst at gmail.com> wrote:> user.should_receive(:encrypt_password).with(your_password) > user.save > > Is this what you want? > > On Fri, Jun 20, 2008 at 10:12 AM, Csongor Bartus <lists at ruby-forum.com> wrote: >> hi all, >> >> i''m learning rspec and i can''t figure out how to test if a callback is >> executed in a model. >> >> my model code is: >> >> class User < ActiveRecord::Base >> before_save :encrypt_password >> >> ... >> >> def encrypt(password) >> self.class.encrypt(password, salt) >> end >> >> >> thanks a lot, >> cs. >> -- >> Posted via http://www.ruby-forum.com/. >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-20 16:01 UTC
[rspec-users] before_save model callback rspec testing
Thanks Pat, I''ve tried this way but the test did not passed ... I''m trying to Rspec Authorization''s plugin User class (http://www.writertopia.com/developers/authorization) Which looks like this: # == Schema Information # Schema version: 92 # # Table name: users # # id :integer(11) not null, primary key # login :string(255) # email :string(255) # crypted_password :string(40) # salt :string(40) # created_at :datetime # updated_at :datetime # remember_token :string(255) # remember_token_expires_at :datetime # require ''digest/sha1'' class User < ActiveRecord::Base # Relationships # ------------- has_many :roles, :dependent => :destroy # Authentication plugins # ---------------------- acts_as_authorized_user acts_as_authorizable # Callbacks # --------- # for Authentication before_save :encrypt_password # methods from the Authentication plugin # -------------------------------------- # Hardwired roles def has_role?( role, authorized_object = nil ) # - site admin return true if self.login.downcase == ''admin'' and (role == ''admin'' or role == ''site_admin'') super end # Authenticates a user by their login name and unencrypted password. Returns the user or nil. def self.authenticate(login, password) u = find_by_login(login) # need to get the salt u && u.authenticated?(password) ? u : nil end # Encrypts some data with the salt. def self.encrypt(password, salt) Digest::SHA1.hexdigest("--#{salt}--#{password}--") end # Encrypts the password with the user salt def encrypt(password) self.class.encrypt(password, salt) end def authenticated?(password) crypted_password == encrypt(password) end def remember_token? remember_token_expires_at && Time.now.utc < remember_token_expires_at end # These create and unset the fields required for remembering users between browser closes def remember_me self.remember_token_expires_at = 2.weeks.from_now.utc self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") save(false) end def forget_me self.remember_token_expires_at = nil self.remember_token = nil save(false) end protected def encrypt_password return if password.blank? self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record? self.crypted_password = encrypt(password) end def password_required? crypted_password.blank? || !password.blank? end end I''ve managed to Rspec the following tests (copying from Rspec output): User validations - :login must be present - :email must be present - :password must be present - :password_confirmation must be present - :login length must be 2..40 - :email length must be 2..40 - :password length must be 2..40 - :login must be unique - :email must be unique - :login must not contain < > + : ; ! # $ % ^ & * / - :email must not contain < > + : ; ! # $ % ^ & * / - :password must not contain < > + : ; ! # $ % ^ & * / and User Acts As Authenticated Authentication - cannot login with empty username and empty password - cannot login with valid username and empty password - cannot login with empty username and valid password - cannot login with invalid username - cannot login with invalid password - can login with valid username and valid password - there can be two passwords with the same value But when I''m trying to test if the password is encrypted I''m getting errors. I''m trying "your" way: u = User.create(:login => "test", :email => "test at test.com", :password => "test123", :password_confirmation => "test123") u.crypted_password.should_not be_nil the error message is: NoMethodError in ''User ActiveRecord Callbacks before save encrypts password'' You have a nil object when you didn''t expect it! You might have expected an instance of Array. The error occurred while evaluating nil.each ./spec/models/user_spec.rb:82: [line 82 ia User.create(...) and "my" way: @user = User.new @user.login = "test" @user.email = "test at test.com" @user.password = "test123" @user.password_confirmation = "test123" @user.save @user.crypted_password.should_not be_nil the error message is: ''User Acts As Authenticated encrypts password'' FAILED expected not nil, got nil -- Posted via http://www.ruby-forum.com/.
David Chelimsky
2008-Jun-20 16:04 UTC
[rspec-users] before_save model callback rspec testing
On Jun 20, 2008, at 11:01 AM, Csongor Bartus wrote:> I''m trying "your" way: > > u = User.create(:login => "test", :email => "test at test.com", :password > => "test123", :password_confirmation => "test123") > u.crypted_password.should_not be_nil > > the error message is: > NoMethodError in ''User ActiveRecord Callbacks before save encrypts > password'' > You have a nil object when you didn''t expect it! > You might have expected an instance of Array. > The error occurred while evaluating nil.each > ./spec/models/user_spec.rb:82: > > [line 82 ia User.create(...) > > > and "my" way: > > @user = User.new > @user.login = "test" > @user.email = "test at test.com" > @user.password = "test123" > @user.password_confirmation = "test123" > @user.save > @user.crypted_password.should_not be_nil > > the error message is: > ''User Acts As Authenticated encrypts password'' FAILED > expected not nil, got nilTry using create! or save! - I''ll bet the record is not being saved correctly and you''re not seeing the error.
Csongor Bartus
2008-Jun-20 16:11 UTC
[rspec-users] before_save model callback rspec testing
David Chelimsky wrote:> > Try using create! or save! - I''ll bet the record is not being saved > correctly and you''re not seeing the error.done, still the same errors (exactly) -- Posted via http://www.ruby-forum.com/.
Csongor Bartus
2008-Jun-20 16:15 UTC
[rspec-users] before_save model callback rspec testing
[Offtopic question] I might be paranoic testing if the password is salted/hashed correctly since all my login tests passed? In learning RSpec I find the most important to draw a line and don''t look behind ... but what if, in this case, accidentally something happens with ''digest/sha1'' and the logins will pass but the password will be not crypted? -- Posted via http://www.ruby-forum.com/.
fire up script/console and copy line 82 and try it out. and report the result here. On Fri, Jun 20, 2008 at 11:11 AM, Csongor Bartus <lists at ruby-forum.com> wrote:> David Chelimsky wrote: > >> >> Try using create! or save! - I''ll bet the record is not being saved >> correctly and you''re not seeing the error. > > done, still the same errors (exactly) > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-23 14:59 UTC
[rspec-users] before_save model callback rspec testing
Yi Wen wrote:> fire up script/console and copy line 82 and try it out. and report the > result here.>> u = User.create!(:login => "test", :email => "test at test.com", :password => "test123", :password_confirmation => "test123")NoMethodError: You have a nil object when you didn''t expect it! You might have expected an instance of Array. The error occurred while evaluating nil.each from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1671:in `attributes='' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1505:in `initialize_without_callbacks'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:225:in `initialize'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in `new'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in `create!'' from (irb):1>>-- Posted via http://www.ruby-forum.com/.
You don''t have attr_accessor :password, :password_confirmation in User, do you? You may want to add this and try again On Mon, Jun 23, 2008 at 9:59 AM, Csongor Bartus <lists at ruby-forum.com> wrote:> Yi Wen wrote: >> fire up script/console and copy line 82 and try it out. and report the >> result here. > >>> u = User.create!(:login => "test", :email => "test at test.com", :password => "test123", :password_confirmation => "test123") > NoMethodError: You have a nil object when you didn''t expect it! > You might have expected an instance of Array. > The error occurred while evaluating nil.each > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1671:in > `attributes='' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1505:in > `initialize_without_callbacks'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:225:in > `initialize'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in > `new'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in > `create!'' > from (irb):1 >>> > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-23 15:26 UTC
[rspec-users] before_save model callback rspec testing
Yi Wen wrote:> You don''t have attr_accessor :password, :password_confirmation in > User, do you? You may want to add this and try againI had :password, I''ve added :password_confirmation but still the same:>> u = User.create!(:login => "test", :email => "test at test.com", :password => "test123", :password_confirmation => "test123")NoMethodError: You have a nil object when you didn''t expect it! You might have expected an instance of Array. The error occurred while evaluating nil.each from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1671:in `attributes='' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1505:in `initialize_without_callbacks'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:225:in `initialize'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in `new'' from ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in `create!'' from (irb):1>>-- Posted via http://www.ruby-forum.com/.
Well, at least now we know this is nothing to do with RSpec. My suggestion is that you comment out the code which will be executed during a creation, bit by bit in User (such as before_save) and try to create a user. In this way you can pinpoint where the problem is. On Mon, Jun 23, 2008 at 10:26 AM, Csongor Bartus <lists at ruby-forum.com> wrote:> Yi Wen wrote: >> You don''t have attr_accessor :password, :password_confirmation in >> User, do you? You may want to add this and try again > > I had :password, I''ve added :password_confirmation but still the same: > >>> u = User.create!(:login => "test", :email => "test at test.com", :password => "test123", :password_confirmation => "test123") > NoMethodError: You have a nil object when you didn''t expect it! > You might have expected an instance of Array. > The error occurred while evaluating nil.each > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1671:in > `attributes='' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/base.rb:1505:in > `initialize_without_callbacks'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/callbacks.rb:225:in > `initialize'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in > `new'' > from > ./script/../config/../config/../vendor/rails/activerecord/lib/active_record/validations.rb:726:in > `create!'' > from (irb):1 >>> > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-24 07:56 UTC
[rspec-users] before_save model callback rspec testing
Yi Wen wrote:> Well, at least now we know this is nothing to do with RSpec. My > suggestion is that you comment out the code which will be executed > during a creation, bit by bit in User (such as before_save) and try to > create a user. In this way you can pinpoint where the problem is.Thanks a lot Yi Wen, Now I''ll find out easier where the bug lies ... But how did you realized the bug is not in RSpec but in the code? -- Posted via http://www.ruby-forum.com/.
That''s because you executed the same creation code into the script/console, which has nothing to do with RSpec, and still get the same error message, right? Yi On Tue, Jun 24, 2008 at 2:56 AM, Csongor Bartus <lists at ruby-forum.com> wrote:> Yi Wen wrote: >> Well, at least now we know this is nothing to do with RSpec. My >> suggestion is that you comment out the code which will be executed >> during a creation, bit by bit in User (such as before_save) and try to >> create a user. In this way you can pinpoint where the problem is. > > Thanks a lot Yi Wen, > > Now I''ll find out easier where the bug lies ... > But how did you realized the bug is not in RSpec but in the code? > > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Csongor Bartus
2008-Jun-24 15:20 UTC
[rspec-users] before_save model callback rspec testing
Yi Wen wrote:> That''s because you executed the same creation code into the > script/console, which has nothing to do with RSpec, and still get the > same error message, right? > > YiGotcha :D It seems I''ve got tired ... Thanks a lot! -- Posted via http://www.ruby-forum.com/.