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