Not an RSpec question, but I was led to this problem by starting to use autotest with cucumber and so, however unjustly, I feel that RSpec has to shoulder some of the blame. I have a failing test in my clients_controller test and I cannot figure out what is wrong from the information provided from the test results and the logs. I would appreciate it someone here to take a look at this and show me what I am missing. The test: class ClientsControllerTest < ActionController::TestCase fixtures :entities, :clients def test_should_create_client assert_difference(''Client.count'') do post :create, :client => { :entity_id => 1, :client_status => ''HOLD'', :client_credit_policy => ''CASH'', :client_credit_terms => 0, :effective_from => "19841101000000".to_date, :superseded_after => "20141031235959".to_date } end assert_redirected_to client_path(assigns(:client)) end The model: class Client < ActiveRecord::Base belongs_to :entity validates_associated validates_presence_of :effective_from validate :date_range private def date_range unless effective_from errors.add_to_base("An Effective date is required") \ end if superseded_after errors.add_to_base("Superseded date falls before Effective date") \ if superseded_after < effective_from end end end The test result: /usr/bin/ruby -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb" "test/functional/clients_controller_test.rb" "test/functional/entity_client_controller_test.rb" Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader Started F........ Finished in 1.096921 seconds. 1) Failure: test_should_create_client(ClientsControllerTest) [/usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:51:in `assert_difference'' /usr/lib/ruby/gems/1.8/gems/actionpack-2.2.1/lib/action_view/renderable.rb:81:in `each_with_index'' /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in `each'' /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in `each_with_index'' /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in `assert_difference'' ./test/functional/clients_controller_test.rb:19:in `test_should_create_client'' /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/setup_and_teardown.rb:60:in `__send__'' /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/setup_and_teardown.rb:60:in `run'']: <Client.count> was the expression that failed. <3> expected but was <2>. 9 tests, 10 assertions, 1 failures, 0 errors /usr/bin/ruby -Ilib:test "/usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb" Errors running test:functionals! So, the test client is not being inserted. But I do not see in the test.log any sql that does an INSERT so I am at a loss to explain what is happening. The log: Processing ClientsController#new (for 0.0.0.0 at 2008-11-20 14:21:19) [GET] Rendering template within layouts/application Rendering clients/new Rendered entities/_entity_header (4.6ms) Rendered clients/_client_detail (3.5ms) Rendered shared/_effective_period (3.5ms) Completed in 28ms (View: 24, DB: 4) | 200 OK [http://test.host/clients/new] Client Load (1.5ms) SELECT * FROM "clients" WHERE ("clients"."id" 953125641) Processing ClientsController#show (for 0.0.0.0 at 2008-11-20 14:21:19) [GET] Parameters: {"id"=>"953125641"} Client Load (1.6ms) SELECT * FROM "clients" WHERE ("clients"."id" 953125641) Rendering template within layouts/application Rendering clients/show Entity Load (1.2ms) SELECT * FROM "entities" WHERE ("entities"."id" = 1) Completed in 17ms (View: 10, DB: 8) | 200 OK [http://test.host/clients/953125641] Client Load (1.5ms) SELECT * FROM "clients" WHERE ("clients"."id" 953125641) Processing ClientsController#update (for 0.0.0.0 at 2008-11-20 14:21:20) [PUT] Parameters: {"client"=>{}, "id"=>"953125641"} Client Load (1.6ms) SELECT * FROM "clients" WHERE ("clients"."id" 953125641) Redirected to #<Client:0xb71808c8> Completed in 12ms (DB: 11) | 302 Found [http://test.host/clients/953125641?] -- Posted via http://www.ruby-forum.com/.
On Thu, Nov 20, 2008 at 1:30 PM, James Byrne <lists at ruby-forum.com> wrote:> Not an RSpec question, but I was led to this problem by starting to use > autotest with cucumber and so, however unjustly, I feel that RSpec has > to shoulder some of the blame. > > I have a failing test in my clients_controller test and I cannot figure > out what is wrong from the information provided from the test results > and the logs. I would appreciate it someone here to take a look at this > and show me what I am missing. > > The test: > > class ClientsControllerTest < ActionController::TestCase > > fixtures :entities, :clients > > def test_should_create_client > assert_difference(''Client.count'') do > post :create, :client => { :entity_id => 1, > :client_status => ''HOLD'', > :client_credit_policy => ''CASH'', > :client_credit_terms => 0, > :effective_from => "19841101000000".to_date, > :superseded_after => "20141031235959".to_date > } > end > > assert_redirected_to client_path(assigns(:client)) > end > > > The model: > > class Client < ActiveRecord::Base > > belongs_to :entity > > validates_associated > validates_presence_of :effective_from > validate :date_range > > private > > def date_range > unless effective_from > errors.add_to_base("An Effective date is required") \ > end > if superseded_after > errors.add_to_base("Superseded date falls before Effective date") > \ > if superseded_after < effective_from > end > end > > end > > The test result: > > /usr/bin/ruby -Ilib:test > "/usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb" > "test/functional/clients_controller_test.rb" > "test/functional/entity_client_controller_test.rb" > Loaded suite > /usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader > Started > F........ > Finished in 1.096921 seconds. > > 1) Failure: > test_should_create_client(ClientsControllerTest) > [/usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:51:in > `assert_difference'' > /usr/lib/ruby/gems/1.8/gems/actionpack-2.2.1/lib/action_view/renderable.rb:81:in > `each_with_index'' > /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in > `each'' > /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in > `each_with_index'' > /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/core_ext/test/unit/assertions.rb:47:in > `assert_difference'' > ./test/functional/clients_controller_test.rb:19:in > `test_should_create_client'' > /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/setup_and_teardown.rb:60:in > `__send__'' > /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.1/lib/active_support/testing/setup_and_teardown.rb:60:in > `run'']: > <Client.count> was the expression that failed. > <3> expected but was > <2>. > > 9 tests, 10 assertions, 1 failures, 0 errors > /usr/bin/ruby -Ilib:test > "/usr/lib/ruby/gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb" > Errors running test:functionals! > > > So, the test client is not being inserted. But I do not see in the > test.log any sql that does an INSERT so I am at a loss to explain what > is happening.Without seeing the controller code, I''d guess that the controller uses create, and not create! and that a validation failure is not getting reported anywhere. If so, try changing create to create! and you should get your error. If not, please post the controller code so we can see what else might be up there. Cheers, David> > The log: > > Processing ClientsController#new (for 0.0.0.0 at 2008-11-20 14:21:19) > [GET] > Rendering template within layouts/application > Rendering clients/new > Rendered entities/_entity_header (4.6ms) > Rendered clients/_client_detail (3.5ms) > Rendered shared/_effective_period (3.5ms) > Completed in 28ms (View: 24, DB: 4) | 200 OK > [http://test.host/clients/new] > Client Load (1.5ms) SELECT * FROM "clients" WHERE ("clients"."id" > 953125641) > > > Processing ClientsController#show (for 0.0.0.0 at 2008-11-20 14:21:19) > [GET] > Parameters: {"id"=>"953125641"} > Client Load (1.6ms) SELECT * FROM "clients" WHERE ("clients"."id" > 953125641) > Rendering template within layouts/application > Rendering clients/show > Entity Load (1.2ms) SELECT * FROM "entities" WHERE ("entities"."id" > = 1) > Completed in 17ms (View: 10, DB: 8) | 200 OK > [http://test.host/clients/953125641] > Client Load (1.5ms) SELECT * FROM "clients" WHERE ("clients"."id" > 953125641) > > > Processing ClientsController#update (for 0.0.0.0 at 2008-11-20 14:21:20) > [PUT] > Parameters: {"client"=>{}, "id"=>"953125641"} > Client Load (1.6ms) SELECT * FROM "clients" WHERE ("clients"."id" > 953125641) > Redirected to #<Client:0xb71808c8> > Completed in 12ms (DB: 11) | 302 Found > [http://test.host/clients/953125641?] > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
David Chelimsky wrote:> > Without seeing the controller code, I''d guess that the controller uses > create, and not create! and that a validation failure is not getting > reported anywhere. > > If so, try changing create to create! and you should get your error. >Thank you. You were close enough to the actual situation that I could easily see what had to be done. The main problem (other than my abysmal ignorance) is that I am retro-fitting test to code that I wrote some time ago. In this case client is a role associated to an entity. The clients_controller handles the case where the entity and the client are created together in one pass. I was creating a new client but not a new entity in my test case and so the save was failing because the entity validations were failing. Changing the .save to .save! displayed the actual error in the test and made the entire situation clear to me. My next question is: why would one choose .save/.create over .save!/.create! since the former does not render the error when testing? -- Posted via http://www.ruby-forum.com/.
On 21 Nov 2008, at 14:44, James Byrne wrote:> David Chelimsky wrote: > >> >> Without seeing the controller code, I''d guess that the controller >> uses >> create, and not create! and that a validation failure is not getting >> reported anywhere. >> >> If so, try changing create to create! and you should get your error. >> > > Thank you. You were close enough to the actual situation that I could > easily see what had to be done. > > The main problem (other than my abysmal ignorance) is that I am > retro-fitting test to code that I wrote some time ago. In this case > client is a role associated to an entity. The clients_controller > handles the case where the entity and the client are created > together in > one pass. I was creating a new client but not a new entity in my test > case and so the save was failing because the entity validations were > failing. Changing the .save to .save! displayed the actual error in > the > test and made the entire situation clear to me. > > My next question is: why would one choose .save/.create over > .save!/.create! since the former does not render the error when > testing?The obvious answer is that you may well have a use case where it''s perfectly OK to attempt to save or at least create an invalid object. An example would be a user sign-up page where the User object created from the values put into the form was invalid, but you wanted to just feed back the validation failures to the user so they could have another crack at the form. I can imagine some people might do this with a call to #create! wrapped up in a begin/rescue block, but I''ve always found that sort of thing rather clumsy myself. I''d prefer to see the code check the User#valid? state after a call to #create, then act accordingly. Make sense? Matt
On Fri, Nov 21, 2008 at 9:44 AM, James Byrne <lists at ruby-forum.com> wrote:> David Chelimsky wrote: > >> >> Without seeing the controller code, I''d guess that the controller uses >> create, and not create! and that a validation failure is not getting >> reported anywhere. >> >> If so, try changing create to create! and you should get your error. >> > > Thank you. You were close enough to the actual situation that I could > easily see what had to be done. > > The main problem (other than my abysmal ignorance) is that I am > retro-fitting test to code that I wrote some time ago. In this case > client is a role associated to an entity. The clients_controller > handles the case where the entity and the client are created together in > one pass. I was creating a new client but not a new entity in my test > case and so the save was failing because the entity validations were > failing. Changing the .save to .save! displayed the actual error in the > test and made the entire situation clear to me. > > My next question is: why would one choose .save/.create over > .save!/.create! since the former does not render the error when testing?It''s very common that whoever was filling out a form will want to be notified of any validation errors that may exist from their data entry. If you use #save you can simply check to see if it returned true or false, and then render the appropriate template. e.g: def create @user = User.new params[:user] if @user.save # yay success else render :action => "new" end end If you use #save! then your controller action has to rescue the exception in order to render the right page. Based on where/how you assign the instance variables you may need to introduce a inner begin/rescue block which makes the action more clunky and less aesthetically appealing. def create @user = User.new params[:user] @user.save! rescue ActiveRecord::RecordInvalid render :action => "new" end If you use .create! then your controller action doesn''t have access to an instance variable which may be needed to render the appropriate template. def create @user = User.create! params[:user] rescue ActiveRecord::RecordInvalid render :action => "new" end -- Zach Dennis http://www.continuousthinking.com http://www.mutuallyhuman.com
Bah, hit send on accident... here''s the last create! example... def create @user = User.create! params[:user] rescue ActiveRecord::RecordInvalid # this won''t work, because @user never gets assigned, since create! raised an exception render :action => "new" end In any of the cases where you have to rescue an exception in a controller action that will have the same affect of your test not reporting the exception. If your application can handle returning a default error page to the user then you''re probably okay, but if you need to re-render something for the user (like the data entry form) then you won''t want un-rescued exceptions for things like validation to occur. And then you may not want to rescue exceptions at all, and you might just end back up with #save. HTH, -- Zach Dennis http://www.continuousthinking.com http://www.mutuallyhuman.com
On Sun, Nov 23, 2008 at 10:51 AM, Zach Dennis <zach.dennis at gmail.com> wrote:> > def create > @user = User.create! params[:user] > rescue ActiveRecord::RecordInvalid > # this won''t work, because @user never gets assigned, since > create! raised an exception > render :action => "new" > end > > In any of the cases where you have to rescue an exception in a > controller action that will have the same affect of your test not > reporting the exception. If your application can handle returning a > default error page to the user then you''re probably okay, but if you > need to re-render something for the user (like the data entry form) > then you won''t want un-rescued exceptions for things like validation > to occur. And then you may not want to rescue exceptions at all, and > you might just end back up with #save. >This is just an example of the general principle that one should not use exception handling for control flow. Exceptions were designed in Ruby (as in other languages) to handle exception circumstances; in particular, when the code that causes the problem does not necessarily know how to handle the problem. Then, exception handling represents a sort of non-local goto. For unexceptional circumstances (such as a user leaving a form field blank), exceptions are expensive and harder to understand than simply checking the return value of a method. That said, I see lots of code where #save and #create are called without checking the return value. I don''t bother checking the return value when "nothing could go wrong." But that''s what #save! and #create! are for. ///ark -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20081124/0cdf9fdc/attachment-0001.html>
Matt Wynne wrote:> > Make sense? > MattYes. I am afraid that my original post is based upon a naive sense of how things work in this environment. Clearly, whenever one is dealing with human input then the possibility of incomplete, contradictory, or simply wrong data must be accommodated as elegantly as is possible. I was overmuch concerned with testing at that moment to give the other issues their due. I have since run across the construct shown below and have used it in the functional test rather than changing the controller code for testing. # This code extends the subject controller to # display errors raised in the controller code # in the test results require ''clients_controller'' class ClientsController; def rescue_action(e) raise e end; end # back to our test -- Posted via http://www.ruby-forum.com/.
On 24 Nov 2008, at 17:56, James Byrne wrote:> Matt Wynne wrote: > >> >> Make sense? >> Matt > > Yes. I am afraid that my original post is based upon a naive sense of > how things work in this environment. Clearly, whenever one is dealing > with human input then the possibility of incomplete, contradictory, or > simply wrong data must be accommodated as elegantly as is possible. I > was overmuch concerned with testing at that moment to give the other > issues their due. > > I have since run across the construct shown below and have used it in > the functional test rather than changing the controller code for > testing. > > # This code extends the subject controller to > # display errors raised in the controller code > # in the test results > require ''clients_controller'' > class ClientsController; def rescue_action(e) raise e end; end > # back to our testCareful. That looks to me like you''re changing the controller code for testing. How come your controller doesn''t raise these errors anyway? I think you have a deeper problem here. The reason you asked this question, IIRC, is because your test code created a model which was not valid, and therefore when the controller tried to save it, you got some behaviour you didn''t expect. You might want to look at using a more standardised mechanism for creating test objects, such as the factory_girl plug-in from throughbot. That way, you can test that each of the objects produced by the factory are valid, and you won''t get tripped up like this in the future. At the very least, when you create your test object instance, just quickly check that it''s valid: before(:each) do @dog = Dog.new(:legs = 3) @dog.should be_valid end cheers, Matt