Setup method in tests

Is there any particular reason why any code you put in your test case setup methods has to be run after the rails code to load the fixtures for the test case? (Other than "because that's the way the code is", of course...) Sometimes it can be useful to be able to run some code before the fixtures get loaded.

Rebecca

Is there any particular reason why any code you put in your test case setup methods has to be run after the rails code to load the fixtures for the test case? (Other than "because that's the way the code is", of course...) Sometimes it can be useful to be able to run some code before the fixtures get loaded.

What's the code you have in mind? The current implementation of fixtures leaves a lot to be desired, but we're hoping to tidy it up for 2.0.

What’s the code you have in mind?

I have things in the database that rails doesn’t like to be in the database - namely triggers.

The database uses a star schema/class-table inheritance setup for parties. A Party is either a Person or an Organisation. A Party has contact details of various types. Inserting a Person/Organisation triggers an insert into the parties table, retrieves the id value, and uses that as the id for the new Person/Organisation.

I’ve got my rails models to work with this setup - there were a few issues, but there are workarounds.

My code relies on the fact that when I save a new Person/Organisation, the Party is also saved - so I need the triggers in the test database. If you load up the :people fixture, then the parties table gets populated too. In the setup method, before loading the fixtures, the old ones are deleted - except this method doesn’t know about the rows in parties that it needs to delete. These rows reference other tables, which then throw database errors when the setup method tries to delete them. It’s fine if you run a single TestCase using transactional fixtures. If you try and run more than one test case, then the setup method throws errors for the second and any further TestCases that use fixtures related to parties/people/organisations/contact details for the above.

The simple way to fix this is to run: Party.delete_all Party.connection.reset_pk_sequence!(‘parties’) before running the code to set up fixtures… except rails doesn’t allow you to do this.

I’ve tried every workaround I can think of, and can’t get any of them to work. I’ve also tried hacking the case statement in TestCase.method_added, adding this:

when ‘setup_before_fixtures’

      define_method(:setup) do
        setup_before_fixtures
        setup_with_fixtures
      end

and defining in my TestCase:

def setup_before_fixtures Party.delete_all

Party.connection.reset_pk_sequence!('parties')

end

but I’m obviously misunderstanding what’s going on in method_added, since this method doesn’t appear to be getting run.

The current implementation of fixtures leaves a lot to be desired, but we’re hoping to tidy it up for 2.0.

Sounds good!

Rebecca

I wrote a small plugin a while ago that alters how the setup and teardown methods work. With minor changes it should let you do what you want. http://svn.viney.net.nz/things/rails/plugins/testcase_setup_and_teardown_with_blocks/README

-Jonathan.

but I'm obviously misunderstanding what's going on in method_added, since this method doesn't appear to be getting run.

A bit of extra logging cleared this one up for me. Here is a bit of a hack to get this working:

      def self.method_added(method)         case method.to_s         when 'setup'           # edit to prevent overriding the setup method created if setup_before_fixtures method defined           unless method_defined?(:setup_without_fixtures) || method_defined?(:setup_after_user_setup)             alias_method :setup_without_fixtures, :setup             define_method(:setup) do               setup_with_fixtures               setup_without_fixtures             end           end         when 'teardown'           unless method_defined?(:teardown_without_fixtures)             alias_method :teardown_without_fixtures, :teardown             define_method(:teardown) do               teardown_without_fixtures               teardown_with_fixtures             end           end         when 'setup_before_fixtures'           # add some processing prior to loading fixtures           unless method_defined?(:setup_after_user_setup)             alias_method :setup_after_user_setup, :setup             define_method(:setup) do               setup_before_fixtures               setup_after_user_setup             end           end         end       end

In your test case, define method 'setup_before_fixtures' and the code will get run before the fixtures. If you also want to add some setup code that runs after the fixtures are loaded, you still can, by defining method 'setup' before you define 'setup_before_fixtures' (yes, I know that's really horrible).

but I'm obviously misunderstanding what's going on in method_added, since this method doesn't appear to be getting run.

A bit of extra logging cleared this one up for me. Here is a bit of a hack to get this working:

      def self.method_added(method)         case method.to_s         when 'setup'           # edit to prevent overriding the setup method created if setup_before_fixtures method defined           unless method_defined?(:setup_without_fixtures) || method_defined?(:setup_after_user_setup)             alias_method :setup_without_fixtures, :setup             define_method(:setup) do               setup_with_fixtures               setup_without_fixtures             end           end         when 'teardown'           unless method_defined?(:teardown_without_fixtures)             alias_method :teardown_without_fixtures, :teardown             define_method(:teardown) do               teardown_without_fixtures               teardown_with_fixtures             end           end         when 'setup_before_fixtures'           # add some processing prior to loading fixtures           unless method_defined?(:setup_after_user_setup)             alias_method :setup_after_user_setup, :setup             define_method(:setup) do               setup_before_fixtures               setup_after_user_setup             end           end         end       end

In your test case, define method 'setup_before_fixtures' and the code will get run before the fixtures. If you also want to add some setup code that runs after the fixtures are loaded, you still can, by defining method 'setup' before you define 'setup_before_fixtures' (yes, I know that's really horrible).

Thanks! Rebecca