[Rails] maddening intermittent failures in unit tests with
"working" code
Chris
otipher at yahoo.com
Wed Mar 1 01:16:15 GMT 2006
Hi all,
This testing problem has been a sink for time today, and is still unresolved.
Basically I have some unit tests that test simple functions (example below)
that depend on join operations in a habtm relationship, and I suspect I am
getting "false" failures, i.e ones that do not logically make any sense. I
need fresh sets of eyes to take a look and see if I'm mising something (my
error, rails bug?, mysql bug?).
It's almost as though there is a race condition somewhere, or an unreliable
SQL transaction.
def reservations
# called by User object, returns count of reservations with associated Zimp
objects
# Zimp and User are AR classes mapped to MySQL schema shown later below.
count = 0
self.zimps.each { |x| count += x.reserved.to_i }
count
end
A typical unit test for this function would be to create a User object and
call the function, and check the return result
def test_working
@user=User.find(:first)
assert_equal 2, @user.reservations
end
For the test data loaded from the fixtures below, two records should be
returned, and the result should be 2. 90% of the time in testing this is what
happens.
But sometimes this will fail with a result of zero (no matching records, i.e.
the join operation produced no output). "Sometimes" means that typically in
reptitive runs in the same environment it will continue to fail, until I make
unrelated code changes, e.g. adding logger output, adding more code somewhere
else, adding a test. etc.
I have tried running tests with rake, from within the radrails environment,
from script/console, and with a coverage tool. Eventually I have reproduced
the failure in multiple environments.
I have included most the information I think could be of use, including the
test_helper.rb configuration, including a mod that disables constraint
checking in SQL (without this, the tests fail).
At a loss...
thanks
Chris
================== Extra info ===========
The SQL produced by the reservations function is:
SELECT * FROM zimps LEFT JOIN users_zimps ON zimps.id = users_zimps.zimp_id
WHERE (users_zimps.user_id = 5 )
SCHEMA
------
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
[....]
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `users_zimps` (
`zimp_id` int(10) unsigned NOT NULL default '0',
`user_id` int(10) unsigned NOT NULL default '0',
`reserved` int(10) unsigned NOT NULL default '1',
KEY `fk_reservations_zimp` (`zimp_id`),
KEY `fk_reservations_user` USING BTREE (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `zimps` (
`id` int(11) NOT NULL auto_increment,
[...]
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
users_zimps.yml
---------------
alice_buys_chris_bday_qty1:
zimp_id: 1
user_id: 5
reserved: 1
alice_buys_chris_bday_qty2:
zimp_id: 3
user_id: 5
reserved: 1
users.yml
---------
otipher:
id: 1
bunky:
id: 2
email_bob:
id: 3
email_sally:
id: 4
alice:
id: 5
zimps.yml
---------
otipher_bday_codebook:
id: 1
otipher_bday_headfirst:
id: 2
otipher_bday_cookbook:
id: 3
test_helper.rb
--------------
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'
require 'logger'
class Test::Unit::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
# From http://rails.techno-weenie.net/tip/2005/11/20/log_within_tests
def logger
RAILS_DEFAULT_LOGGER
end
end
# from
http://wiki.rubyonrails.com/rails/pages/DisableForeignKeyChecksUnderMySql
class Fixtures
alias :original_delete_existing_fixtures :delete_existing_fixtures
alias :original_insert_fixtures :insert_fixtures
def delete_existing_fixtures
@connection.update "SET FOREIGN_KEY_CHECKS = 0", 'Fixtures deactivate
foreign key checks.';
original_delete_existing_fixtures
@connection.update "SET FOREIGN_KEY_CHECKS = 1", 'Fixtures activate
foreign key checks.';
end
def insert_fixtures
@connection.update "SET FOREIGN_KEY_CHECKS = 0", 'Fixtures deactivate
foreign key checks.';
original_insert_fixtures
@connection.update "SET FOREIGN_KEY_CHECKS = 1", 'Fixtures activate
foreign key checks.';
end
end
More information about the Rails
mailing list