[rspec-users] Rails' fixtures suck! But what about something like this?

Chris Hoffman bosshoff at gmail.com
Sun Jul 22 08:39:38 EDT 2007

Have you tried just using fixture scenarios?  Did it work?

On 5/21/07, Carl Lerche <carl.lerche at gmail.com> wrote:
> Sorry about the very long email, but this is a hairy topic that's been
> annoying me for some time and I decided to try to do something about.
> Also, if you got this twice, I apologize too, but it didn't seem to
> have successfully gone out the first time.
> Background:
> ----------
> I've been dealing with Rails for about a year and a half now. I've
> been using Rails' built in testing framework, and it's fine... until I
> really have to start dealing with the fixtures. I am currently working
> on an application that really focuses on selecting data using complex
> logic. The only way to test the application in a meaningful way is by
> using a large number of fixtures. This has become a real nightmare to
> manage and I almost am spending more time keeping the fixtures up to
> date than I am coding or testing. So, I took a moment, stepped back,
> and took a good look at how I could I could improve fixtures to make
> my life a lot easier.
> I have gotten a quick and dirty prototype of my solution running, but
> before I really roll up my sleeves and start polishing it up, I
> thought I would try to get some suggestions from the community.
> Overview:
> ---------
> In my experience, the current fixture framework has three main problems:
> - There is no way to create different version of fixtures. What I mean
> by this is that you only can have one users.yml file even if your
> tests depend on different initial conditions. What this usually means
> is that you will just keep tagging on to the end of users.yml even
> though it is not the most efficient way to do it.
> - Managing relationships between tables is a really big pain. One must
> manually keep track of IDs. This can quickly become a major headache.
> - There is no clean way to quickly generate data. If  I want 50
> records that I could easily generate in a loop, I still gotta write
> them by hand (at least, I wasn't able to figure out how to add loops
> to my yaml files in a clean way).
> - There is a lot of repetition. No way to follow DRY.
> Solution:
> ---------
> + Versioned Fixtures
> First, to address the fixture "versions", I thought the easiest way to
> do this would be scenarios (I was inspired from fixture-scenarios).
> The way fixtures could be laid out is as follows:
> + specs
> |- fixtures
>    |- global
>    |- only_one_signed_up_user
>    |- lots_of_posts_in_los_angeles
>    |- ...
> All global fixtures (fixtures that should be loaded before every spec)
> go into global, then, for each different scenario, there is a
> directory created with the relevant fixtures in there. Then, in the
> specs, you could do the following
> -------------------------------
> require File.dirname(__FILE__) + '/../spec_helper'
> describe User, :when => :only_one_signed_up_user do
>   it "should be the only user" do
>     User.count.should == 1
>   end
> end
> -------------------------------
> The key part here would be the :when => :scenario_name option to the
> describe method.
> + Writing the fixtures
> Writing fixtures with YAML is quite ugly. I think a better way to do
> it would be using a DSL, but coming up with a good syntax is hard.
> This is where I am the most hesitant. I have two "options" and I was
> wondering if people could comment on them and give me some feedback
> and suggestions.
> - The first option is how I started out: http://pastie.caboo.se/63359
> In this option, fixtures for multiple tables can be written in a
> single file. You would start out by using the _create_ method to tell
> the parser what table the fixtures are for and you could also specify
> :with, which would set default attributes for fixtures.
> You could also nest fixtures in order to easily scope them (see the
> last user fixture how I specified nested post fixtures).
> - The second option is what I currently prefer: http://pastie.caboo.se/63361
> In this option, I keep the one table per file concept that is
> currently used. As such, we don't need to specify what table we want
> to use before hand. I make available a with_options method which lets
> you set default attributes for fixtures. It's also easy to create
> loops to automatically generate fixtures, as I show in the second half
> of the file. The f method is the actual method for creating a fixture.
> it takes a name as a string and a block in which the attributes of the
> fixtures are specified. However, the method_missing method is
> implemented to handle any missing methods and use that to create
> fixtures too as seen with fixture_name { ... }
> + Dealing with relationships
> I think what I hate the most about fixtures right now is having to
> deal with table relationships. Having to keep track of IDs myself is
> horrible. So, I thought that the easiest way to do this is making the
> table_name(:fixture_name) method available straight inside the
> fixtures. So, if I have a user model that has a location associated
> with it (let's say a zip code, longitude, and latitude), instead of
> having to copy / paste that data across fixtures, I can do the
> following:
> -------------------------------
> local_guy {
>   zip_id        zips(:portland)
>   longitude     zips(:portland).longitude
>   latitude      zips(:portland).latitude
> }
> -------------------------------
> This is much easier to deal with than the other way around. This also
> introduces dependencies between fixtures, I thought the easiest way to
> handle it would be adding a fixture_order configuration:
> -------------------------------
> Spec::Runner.configure do |config|
>   config.fixture_order = :zips, :categories, :users, :posts
> end
> -------------------------------
> + What's not solved with this
> I haven't figured out a good way to handle counter_cache columns.
> Right now, this would still require you to manually count how many
> fixtures you have associated with a parent and add that to the
> counter_cache column. Any ideas of a better way to do this?
> Well, that's all I came up with. I'm going to keep hacking away at
> this and hopefully you all have some feedback to improve this concept.
> --
> EPA Rating: 3000 Lines of Code / Gallon (of coffee)
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

More information about the rspec-users mailing list