load fixtures in setup? (or is it test-spec's fault)

Railsters:

For various reasons, not worth discussing here, we'd really prefer to
load fixtures like this:

  class MySuite < etc::TestCase
    def setup
      fixtures :posts, :forums, :whatnots
    end
    ...
  end

Does anyone know how to call the same thing fixtures calls, and how to
put it inside the setup?

What are the reasons? Oh, okay...

deep breath<

We have a very project with various Rails 1.2 and 2.1 applications
using elaborate test fixtures that roughly correspond to established
databases with hundreds of thousands of records. We have many Abstract
Tests, and many of our cases have very elaborate setups. We are trying
to start using test-spec, and we already use scenario-fixtures.

To clean up our testage, we would like to use test-spec like this
(warning - pseudo-Ruby):

  context 'generic' do
    fixtures :posts, :forums, :whatnots
    setup{ foo }
    specify 'foo things' { foo things}
    specify 'more foo things' { more foo things}

    context 'specific' do
      setup{ bar }
      specify 'bar things' { foo & bar things}
      specify 'more bar things' { etc}
    end
  end

The point (the only point of BDD I can detect so far) is (at the
possible risk of less AbstractTest flexibility), we can inherit setups
without the (faint) burden of excessive modules and 'include' lines.

However, my feeb experiments with test-spec show that setup{bar}
cannot see the outer context's fixtures. This is either pilot error,
or it is unprincipled and counterintuitive. Ideally, the fixtures
should inherit and accumulate as one descends deeper into nested
contexts.

Next, fixture_scenarios seems to throw an exception if we get too
creative with the nested setups and fixtures. We will eventually go in
after that issue.

So the easiest short-term fix to all this fun would appear to be using
setups to, uh, set each test case up, the way certain industry thought-
leaders intended. Putting fixtures() at class scope is syntactic
sugar, and our tests can only get so sweet.

Railsters:

For various reasons, not worth discussing here, we'd really prefer to
load fixtures like this:

class MySuite < etc::TestCase
   def setup
     fixtures :posts, :forums, :whatnots
   end
   ...
end

Does anyone know how to call the same thing fixtures calls, and how to
put it inside the setup?

Well you could look at fixtures.rb in activerecord, that's where the
magic happens. There's a setup hook in there for fixtures which might
be interesting. If I recall correctly, the fixtures method just sticks
what you give it in some class variable for the setup thing to pickup.
In the interest of speed a given fixtures will only ever be loaded
once(at least in stock rails. Plugins that add to the fixtures
functionality may overhaul that)

Fred

Frederick Cheung wrote:

Well you could look at fixtures.rb in activerecord, that's where the
magic happens.

You always find something in the last place you look, huh?

  def self.fixtures(*table_names)
    write_inheritable_attribute("fixture_table_names", table_names)
  end

  def setup
    instantiate_fixtures(*fixture_table_names) if fixture_table_names
  end

If that's it, how does our setup call their setup without super?

instantiate_fixtures doesn't do what I think you think it does - that's the think which creates instance variables for each loaded fixtures.

I'm not entirely sure what you're asking - is the above your proposed solution to your problem?

Fre

I'm not entirely sure what you're asking

I don't want to write this:

  fixtures :tables tables tables
  def setup
  end

I want to write this:

  def setup
    x :tables tables tables
  end

The thing that reads the YAML files and INSERTs them into the database
- I called it 'x' in my pseudo-Ruby - I want to call it from inside
setup, not outside.

- is the above your proposed
solution to your problem?

It's the code near self.fixtures, from fixtures.rb, that you pointed
out.

For various reasons, not worth discussing here, we'd really prefer to
load fixtures like this:

I whipped out some Beast, and commented 'fixtures :all' from
test_helper.rb. This doesn't work:

class SessionTest < ActiveSupport::TestCase
  def setup
    self.class.fixtures :posts, :users
  end

  def test_fixtures
    p posts(:pdi_reply)
    p users(:sam)
  end
end

It doesn't crass at the self.class.fixtures line, but then no posts
nor users exist.

What is so special about self.fixtures, or whatever the fixtures, that
I can't just call it wherever I like?

This doesn't work:
def setup
self.class.fixtures :posts, :users
end

Here's how to do it. I read activerecord/test/fixtures_test.rb
(following my own frequent advice that unit tests are the best
documentation), and it lead me to load_extra_fixture(). Upgrading that
to handle multiple fixtures gives this monstrosity:

require 'test_helper'
require 'assert2'

class SessionTest < ActiveSupport::TestCase

  def nab_fixtures(*names)
    names.each do |name|
      fixture = create_fixtures(name)
      assert fixture.is_a?(Fixtures)
      @loaded_fixtures[fixture.table_name] = fixture
    end
    self.class.setup_fixture_accessors(names)
  end

  def setup
    nab_fixtures :posts, :users
  end

  def test_truth
    assert{ posts(:pdi_reply) }
    assert{ users(:sam) }
  end
end

Aaaaand now I have to figure out how to get test-spec to call it...

For various reasons, not worth discussing here, we'd really prefer to
load fixtures like this:

I whipped out some Beast, and commented 'fixtures :all' from
test_helper.rb. This doesn't work:

class SessionTest < ActiveSupport::TestCase
def setup
   self.class.fixtures :posts, :users
end

def test_fixtures
   p posts(:pdi_reply)
   p users(:sam)
end
end

It doesn't crass at the self.class.fixtures line, but then no posts
nor users exist.

What is so special about self.fixtures, or whatever the fixtures, that
I can't just call it wherever I like?

The reason that this doesn't work is that activerecord hooks into into
the setup method and inserts its fixture loading code before your
setup runs, so when you call self.class.fixtures it's too late.

Fred