Test::Unit Functional failure puzzle


#1

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:ineach_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:ineach_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:intest_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:inrun’]:
    <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?]


#2

On Thu, Nov 20, 2008 at 1:30 PM, James B. removed_email_address@domain.invalid
wrote:

      :effective_from => "19841101000000".to_date,

class Client < ActiveRecord::Base
unless effective_from

Finished in 1.096921 seconds.
`each_with_index’
<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


#3

David C. 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?


#4

On Fri, Nov 21, 2008 at 9:44 AM, James B. removed_email_address@domain.invalid
wrote:

Thank you. You were close enough to the actual situation that I could

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 D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com


#5

On Sun, Nov 23, 2008 at 10:51 AM, Zach D. removed_email_address@domain.invalid
wrote:

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


#6

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 D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com


#7

Matt W. 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 test


#8

On 24 Nov 2008, at 17:56, James B. wrote:

was overmuch concerned with testing at that moment to give the other
class ClientsController; def rescue_action(e) raise e end; end

back to our test

Careful. 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


#9

On 21 Nov 2008, at 14:44, James B. wrote:

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