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.

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 Garvin wrote:

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 Garvin 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 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.

Jon Garvin wrote:

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?

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 Manges