Test Fixture Alternatives

Didn’t get any responses to my previous posting of this, so I figured
I’d try once more now that the holidays are over and people are
hopefully getting back into the swing.

We’ve run into an issue on a project with one fixture that’s failing
because it’s getting loaded before another fixture that it’s dependent
on. Only happens on one test. Many other tests that use both fixtures
work fine. After a little searching on the net, I find that we’re not
the first to run into issues with the order in which fixtures get
loaded. The best solution I’ve found mentioned is pretty much total
abandonment of fixtures and instead using helper methods that create
appropriate data. The advantages seem to be a) solving the load order
problem we’re having and b) tests run faster. Nowhere that I see this
talked about do I see people discuss any disadvantages, so… my
questions are?

Are there any disadvantages to using helper methods instead of fixtures?
What are they?

If helper methods really are more advantageous than fixtures, why isn’t
it standard procedure to create the helper methods from the beginning?
Every bit of documentation I’ve read in regards to getting started in
testing says to create fixtures, with no hint of other, potentially more
appropriate, means of getting test data into the database.

Are there any other solutions to our problem that I haven’t discovered?

What’s the specific problem you’re having. I’m not sure this will help,
but
some people are moving to mocks instead of fixtures when database
functionality is not what’s under test.

The fixture names are kept in a table_name=>fixture hash so order is not
guaranteed. I know the Engines people (I believe canadaduane) wrote some
extensions to help with fixture flexibility, but as I recall it was to
allow
you to have more than one possible fixture for a given model. Their code
might help you find a way to tweak the order.

–steve

Jon G. wrote:

work fine. After a little searching on the net, I find that we’re not


View this message in context:
http://www.nabble.com/-Rails--Test-Fixture-Alternatives-tf2909204.html#a8131685
Sent from the RubyOnRails Users mailing list archive at Nabble.com.

s.ross wrote:

What’s the specific problem you’re having.
A simplified example would be something like rather than hard coding the
id’s for a has_many-> belongs_to relationship between two models, the
second looks up who it belongs to via code… eg.

thing:
owner_id: <%= Owner.find_by_name(‘Joe’).id %>

which is more flexible, and a lot clearer when looking at the yaml file
than…

owner_id: 23

and works fine as long as the owners.yml file gets loaded before the
things.yml. But when owners.yml hasn’t been loaded yet, things.yml
obviously croaks. With all the tests we’ve got that load fixtures like
this, it’s kind of amazing we just now ran into this issue. We’ve been
assuming all this time that the fixtures were loading in the order we
presented them with no reason to think otherwise, since it all worked
great.

Jon G. wrote:

We’ve run into an issue on a project with one fixture that’s failing
because it’s getting loaded before another fixture that it’s dependent
on. Only happens on one test. Many other tests that use both fixtures
work fine.

At a guess, go to the top of the /test/fixture/module.yml file that
needs the other fixtures, and add this line:

<% load_fixture(‘some_other_model.yml’) %>

You gotta write the load_fixture method; it will have something to do
with the
Fixtures.create_fixtures() method.


Phlip
http://c2.com/cgi/wiki?ZeekLand ← NOT a blog!!

Jon G. wrote:

loaded. The best solution I’ve found mentioned is pretty much total
it standard procedure to create the helper methods from the beginning?
Every bit of documentation I’ve read in regards to getting started in
testing says to create fixtures, with no hint of other, potentially more
appropriate, means of getting test data into the database.

Are there any other solutions to our problem that I haven’t discovered?

I’ve been using the approach you describe for building fixtures on the
fly.
Basically what I do is write a helper method that I put in the
test/mock file for each model.

This method (called ‘new_fixture’) will generate a new fixture that has
certain properties. It generally can return an empty object, an
invalid object, a valid object, a deleted object, and a non-existent
object.

The valid objects are constructed so that they pass the AR validation
tests, and the invalid ones will fail them. The non-existent object
returns a blank object with its :id set to a value that does not exist
in the test database. A deleted object is one that has it’s
‘deleted_at’ attribute set (as per acts_as_paranoid). This method
gives you the option to save the object in the test db if needed.

This may not be faster than standard fixtures, but you can add a few
assertions to make sure the mock object is returning the correct types
of object (i.e., you can assert that they are valid).

You can now refactor your model knowing that you won’t have to generate
new fixtures or deal with corrupt ones because you changed how the
model works. All you might have to do is update the ‘new_fixture’
method.

_Kevin

s.ross wrote:

some people are moving to mocks instead of fixtures when database
functionality is not what’s under test.

I’m one of them. Unit tests should rarely need fixtures, and
functional tests should not rely on model implementation. The one
challenge with using mocks for functional testing is it is much easier
to do if you have split controller and view tests. Right now I only
know of RSpec and Test::Rails which will do that. I wrote a short
example on my blog about the benefits of using mocks:
http://www.dcmanges.com/blog/16

Dan M.

Phlip wrote:

At a guess, go to the top of the /test/fixture/module.yml file that
needs the other fixtures, and add this line:

<% load_fixture(‘some_other_model.yml’) %>

You gotta write the load_fixture method; it will have something to do
with the
Fixtures.create_fixtures() method.

Hmmm, creative idea. I definitely hadn’t thought of doing anything like
that.