Chris
2006-Mar-01 01:16 UTC
[Rails] maddening intermittent failures in unit tests with "working" code
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
Chris
2006-Mar-01 16:10 UTC
[Rails] Re: maddening intermittent failures in unit tests with
Chris <otipher@...> writes:> > 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?). >Problem solved, this turned out to be that one unit test - user_test.rb - did not include the join table fixtures :users_zimps (though no errors were flagged by rails). Because the other unit test zimp_test.rb did specify the join table fixture loading, it led to random successes and failures for the user_test.rb that did not include the fixture loading. I added somethig under the gotchas section of the wiki - http://wiki.rubyonrails.org/rails/pages/Gotcha - to help others who may encounter this behavior.