Steven Hansen
2006-Aug-15 18:52 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
Hi, I thought I had a handle on the whole singleton class thing but now I''m not too sure. I have a class definition: class ValidationMaster def validate(params) # complex and time consuming validation # returns true on success, raises Exception # on failure end end Okay, so when I''m running my functional tests within rails, I want to be able to control how the validate(params) method behaves. So, I''ve created a ValidationMaster class definition and put it in RAILS_ROOT/test/mocks/test/validation_master.rb The methods I''ve defined there seem to be correctly overriding those of the original class definition. Now here is where I''m having problems. Within certain functional tests, I want validate(params) to return true. Other times I want it to fail and throw an exception. Thus, I can''t rely on the Mock ValidationMaster class definition to take care of this. But then I thought, HEY, within each test I can open up the singleton class for the ValidationMaster class object. Whoo hoo, I''m in charge now! def test_stuff class << ValidationMaster def validate(params) raise ValidationException end end vm = ValidationMaster.new vm.validate("Jeff") end But, when I run my test, the exception is not getting thrown. The methods I''ve defined in the Mock are all working right, but it''s somehow not seeing the override within test_stuff. Am I mistaken here, can I not override the class definition of ValidationMaster like this? Thanks, Steven
James Mead
2006-Aug-15 20:41 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote:> > I thought I had a handle on the whole singleton class thing but now I''m > not too sure. > > I have a class definition: > > class ValidationMaster > def validate(params) > # complex and time consuming validation > # returns true on success, raises Exception > # on failure > end > end > > Okay, so when I''m running my functional tests within rails, I want to be > able to control how the validate(params) method behaves. > > So, I''ve created a ValidationMaster class definition and put it in > RAILS_ROOT/test/mocks/test/validation_master.rb > > The methods I''ve defined there seem to be correctly overriding those of > the original class definition. > > Now here is where I''m having problems. Within certain functional tests, > I want validate(params) to return true. Other times > I want it to fail and throw an exception. Thus, I can''t rely on the > Mock ValidationMaster class definition to take care of this. > > But then I thought, HEY, within each test I can open up the singleton > class for the ValidationMaster class object. Whoo hoo, > I''m in charge now! > > def test_stuff > class << ValidationMaster > def validate(params) > raise ValidationException > end > end > > vm = ValidationMaster.new > vm.validate("Jeff") > end > > But, when I run my test, the exception is not getting thrown. The > methods I''ve defined in the Mock are all working right, but it''s somehow > not seeing > the override within test_stuff. Am I mistaken here, can I not override > the class definition of ValidationMaster like this?I think this is what you want... def test_stuff vm = ValidationMaster.new class << vm def validate(params) raise ValidationException end end vm.validate("Jeff") end However, you might want to consider using Mocha <http://mocha.rubyforge.org>to write the test more concisely... def test_stuff vm = ValidationMaster.new vm.stubs(:validate).raises(ValidationException) vm.validate("Jeff") end Hope that helps. James. http://blog.floehopper.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060815/5fd5ce9e/attachment-0001.html
Steven Hansen
2006-Aug-15 21:43 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
James Mead wrote:> On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote: >> >> I thought I had a handle on the whole singleton class thing but now I''m >> not too sure. >> >> I have a class definition: >> >> class ValidationMaster >> def validate(params) >> # complex and time consuming validation >> # returns true on success, raises Exception >> # on failure >> end >> end >> >> Okay, so when I''m running my functional tests within rails, I want to be >> able to control how the validate(params) method behaves. >> >> So, I''ve created a ValidationMaster class definition and put it in >> RAILS_ROOT/test/mocks/test/validation_master.rb >> >> The methods I''ve defined there seem to be correctly overriding those of >> the original class definition. >> >> Now here is where I''m having problems. Within certain functional tests, >> I want validate(params) to return true. Other times >> I want it to fail and throw an exception. Thus, I can''t rely on the >> Mock ValidationMaster class definition to take care of this. >> >> But then I thought, HEY, within each test I can open up the singleton >> class for the ValidationMaster class object. Whoo hoo, >> I''m in charge now! >> >> def test_stuff >> class << ValidationMaster >> def validate(params) >> raise ValidationException >> end >> end >> >> vm = ValidationMaster.new >> vm.validate("Jeff") >> end >> >> But, when I run my test, the exception is not getting thrown. The >> methods I''ve defined in the Mock are all working right, but it''s somehow >> not seeing >> the override within test_stuff. Am I mistaken here, can I not override >> the class definition of ValidationMaster like this? > > > I think this is what you want... > > def test_stuff > vm = ValidationMaster.new > class << vm > def validate(params) > raise ValidationException > end > end > > vm.validate("Jeff") > end > > However, you might want to consider using Mocha > <http://mocha.rubyforge.org>to write the test more concisely... > > def test_stuff > vm = ValidationMaster.new > vm.stubs(:validate).raises(ValidationException) > vm.validate("Jeff") > end > > Hope that helps. > James. > http://blog.floehopper.org > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/railsI would like to redefine a method at the class object level. Thus any new instances of the ValidationMaster object would have a new definition for the validate(params) method. What you are doing is changing a single instance of the ValidationMaster object. Mocha looks pretty cool, however I''m still a bit new to the whole testing thing so I''d like to get a bit better at it before moving on to something like Mocha. Thanks, Steven
Steven Hansen
2006-Aug-15 21:55 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
Steven Hansen wrote:> James Mead wrote: >> On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote: >>> >>> I thought I had a handle on the whole singleton class thing but now I''m >>> not too sure. >>> >>> I have a class definition: >>> >>> class ValidationMaster >>> def validate(params) >>> # complex and time consuming validation >>> # returns true on success, raises Exception >>> # on failure >>> end >>> end >>> >>> Okay, so when I''m running my functional tests within rails, I want to be >>> able to control how the validate(params) method behaves. >>> >>> So, I''ve created a ValidationMaster class definition and put it in >>> RAILS_ROOT/test/mocks/test/validation_master.rb >>> >>> The methods I''ve defined there seem to be correctly overriding those of >>> the original class definition. >>> >>> Now here is where I''m having problems. Within certain functional tests, >>> I want validate(params) to return true. Other times >>> I want it to fail and throw an exception. Thus, I can''t rely on the >>> Mock ValidationMaster class definition to take care of this. >>> >>> But then I thought, HEY, within each test I can open up the singleton >>> class for the ValidationMaster class object. Whoo hoo, >>> I''m in charge now! >>> >>> def test_stuff >>> class << ValidationMaster >>> def validate(params) >>> raise ValidationException >>> end >>> end >>> >>> vm = ValidationMaster.new >>> vm.validate("Jeff") >>> end >>> >>> But, when I run my test, the exception is not getting thrown. The >>> methods I''ve defined in the Mock are all working right, but it''s somehow >>> not seeing >>> the override within test_stuff. Am I mistaken here, can I not override >>> the class definition of ValidationMaster like this? >> >> >> I think this is what you want... >> >> def test_stuff >> vm = ValidationMaster.new >> class << vm >> def validate(params) >> raise ValidationException >> end >> end >> >> vm.validate("Jeff") >> end >> >> However, you might want to consider using Mocha >> <http://mocha.rubyforge.org>to write the test more concisely... >> >> def test_stuff >> vm = ValidationMaster.new >> vm.stubs(:validate).raises(ValidationException) >> vm.validate("Jeff") >> end >> >> Hope that helps. >> James. >> http://blog.floehopper.org >> >> >> ------------------------------------------------------------------------ >> >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails > > > I would like to redefine a method at the class object level. Thus any > new instances of the ValidationMaster object would have a new definition > for the validate(params) method. What you are doing is changing a > single instance of the ValidationMaster object. > > Mocha looks pretty cool, however I''m still a bit new to the whole > testing thing so I''d like to get a bit better at it before moving on > to something like Mocha. > > Thanks, > Steven > > > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/railsOk, I think I see where I''m going wrong here. Doing: class << ValidationMaster end allows me to add class level methods. So if I had class ValidationMaster def validate() end end and then I did class << ValidationMaster def validate() end end I would essentially have two validiate() methods in the ValidationMaster class. It would be like having this definition: class ValidationMaster def validate() puts "one" end def self.validate() puts "two" end end vm = ValidationMaster.new vm.validate() #=> "one" ValidationMaster.validate() #=> "two" -Steven
James Mead
2006-Aug-15 22:31 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote:> > I would like to redefine a method at the class object level. Thus any > new instances of the ValidationMaster object would have a new definition > for the validate(params) method. What you are doing is changing a > single instance of the ValidationMaster object.You can just re-open the class and redefine the method... # first definition (perhaps in another file) class ValidationMaster def validate() puts "one" end end vm = ValidationMaster.new vm.validate # => "one" # second definition class ValidationMaster def validate() puts "two" end end vm = ValidationMaster.new vm.validate # => "two" Mocha looks pretty cool, however I''m still a bit new to the whole> testing thing so I''d like to get a bit better at it before moving on > to something like Mocha.No worries. James. http://blog.floehopper.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060815/90e9aa0f/attachment.html
Steven Hansen
2006-Aug-15 23:13 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
James Mead wrote:> On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote: >> >> I would like to redefine a method at the class object level. Thus any >> new instances of the ValidationMaster object would have a new definition >> for the validate(params) method. What you are doing is changing a >> single instance of the ValidationMaster object. > > > You can just re-open the class and redefine the method... > > # first definition (perhaps in another file) > class ValidationMaster > def validate() > puts "one" > end > end > > vm = ValidationMaster.new > vm.validate # => "one" > > # second definition > class ValidationMaster > def validate() > puts "two" > end > end > > vm = ValidationMaster.new > vm.validate # => "two" > > Mocha looks pretty cool, however I''m still a bit new to the whole >> testing thing so I''d like to get a bit better at it before moving on >> to something like Mocha. > > > No worries. > > James. > http://blog.floehopper.org > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/railsOk, this does what I was trying to accomplish: class ValidationMaster def validate(params) # complex and time consuming validation # returns true on success, raises Exception # on failure end end def test_validation_fails ValidationMaster.class_eval { def validate(params); raise Exception; end } post(:download, opts) assert_response(:redirect) assert_equal(flash[:error], "Authentication failed: token verification failed") end def test_validation_succeeds ValidationMaster.class_eval { def validate(params); return true; end } post(:download, opts) assert_response(:success) assert_equal(flash[:error], nil) end I don''t want the actual validation to run, I just want a specific result from this method. The result I want differs between tests. Now I can test my controller''s actions without having to have the "real" validation() method executed. Sorry for not giving a better explanation of what I was trying to do. Thanks, Steven
James Mead
2006-Aug-15 23:34 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote:> > Ok, this does what I was trying to accomplish: > > class ValidationMaster > def validate(params) > # complex and time consuming validation > # returns true on success, raises Exception > # on failure > end > end > > def test_validation_fails > ValidationMaster.class_eval { def validate(params); raise Exception; > end } > > post(:download, opts) > assert_response(:redirect) > assert_equal(flash[:error], "Authentication failed: token > verification failed") > end > > def test_validation_succeeds > ValidationMaster.class_eval { def validate(params); return true; end } > post(:download, opts) > assert_response(:success) > assert_equal(flash[:error], nil) > end > > > I don''t want the actual validation to run, I just want a specific result > from this method. The result I want differs between tests. Now I can > test my controller''s actions without having to have the "real" > validation() method executed. Sorry for not giving a better explanation > of what I was trying to do.That does work, but watch out for the gotcha that your method re-definition is not local to the test. So depending on which was the last of these to run, the behaviour in other tests might not be what you expect. This is one of the benefits of Mocha, which restores the original implementation after each test (in a secret teardown). Your tests would become... def test_validation_fails ValidationMaster.any_instance.stubs(:validate).raises(Exception) post(:download, opts) assert_response(:redirect) assert_equal(flash[:error], "Authentication failed: token verification failed") end def test_validation_succeeds ValidationMaster.any_instance.stubs(:validate).returns(true) post(:download, opts) assert_response(:success) assert_equal(flash[:error], nil) end James. http://blog.floehopper.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060815/5d49abcd/attachment.html
Steven Hansen
2006-Aug-15 23:44 UTC
[Rails] Trying to Overide Class Object Methdos For Testing
James Mead wrote:> On 15/08/06, Steven Hansen <runner@berkeley.edu> wrote: >> >> Ok, this does what I was trying to accomplish: >> >> class ValidationMaster >> def validate(params) >> # complex and time consuming validation >> # returns true on success, raises Exception >> # on failure >> end >> end >> >> def test_validation_fails >> ValidationMaster.class_eval { def validate(params); raise Exception; >> end } >> >> post(:download, opts) >> assert_response(:redirect) >> assert_equal(flash[:error], "Authentication failed: token >> verification failed") >> end >> >> def test_validation_succeeds >> ValidationMaster.class_eval { def validate(params); return true; end } >> post(:download, opts) >> assert_response(:success) >> assert_equal(flash[:error], nil) >> end >> >> >> I don''t want the actual validation to run, I just want a specific result >> from this method. The result I want differs between tests. Now I can >> test my controller''s actions without having to have the "real" >> validation() method executed. Sorry for not giving a better explanation >> of what I was trying to do. > > > That does work, but watch out for the gotcha that your method re-definition > is not local to the test. So depending on which was the last of these to > run, the behaviour in other tests might not be what you expect. This is one > of the benefits of Mocha, which restores the original implementation after > each test (in a secret teardown). Your tests would become... > > def test_validation_fails > ValidationMaster.any_instance.stubs(:validate).raises(Exception) > post(:download, opts) > assert_response(:redirect) > assert_equal(flash[:error], "Authentication failed: token verification > failed") > end > > def test_validation_succeeds > ValidationMaster.any_instance.stubs(:validate).returns(true) > post(:download, opts) > assert_response(:success) > assert_equal(flash[:error], nil) > end > > James. > http://blog.floehopper.org > > > ------------------------------------------------------------------------ > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails"That does work, but watch out for the gotcha that your method re-definition is not local to the test." Heh, I was just about to email the list again asking about this. "This is one of the benefits of Mocha, which restores the original implementation after each test (in a secret teardown)." I might using Mocha sooner than I expected. Thanks, Steven