domenica 19 giugno 2011

Machinist vs Factory Girl: Machinist win!

Today I decided to verify if Machinist could be a good replacement for Factory Girl. In our project, we have a big problem with Factory Girl: even if you tell her not to hit the database, using the Factory.build method, if an object has associations, these are saved on the DB. And this causes a huge slowdown in specs using factories. We've been using Factory Girl for nearly two years, and if we could find a way to stop him hitting the DB, we could really have a huge improvent in our test suite running time.



To verify if Machinist could perform better, I set up a basic rails app. Look at this example:





If you do a tail -f log/test.log and you run this spec, you'll see something like this:





The Factory.build method has to save dependencies on the DB to set the foreign keys on the objects and validate them.



Let's try with machinist:





This time, running tail on the test.log file and running the spec, doesn't shown any DB hit, and of yeah, we have a green test.



I verified this also by putting a debugger line after the validation and inspecting the DB from within the debugger after the validation has run - with FactoryGirl, it revealed an Address object saved on the DB, while with Mechanist it didn't.



I still haven't looked inside machinist to show how it handles this, but I'll do it soon, so keep in touch!

10 commenti:

  1. Worth noting that this is all with Machinist 2. Machinist 1 works a bit differently.

    As for what happens under the hood, Machinist relies on ActiveRecord to do the heavy lifting when saving objects.

    When you call make! (to create and save an object, rather than just creating it in memory), Machinist builds the object and all its associations in memory, then calls save! on the parent object only. ActiveRecord takes care of saving all the associated objects that need to be saved.

    That said, do have a look at the Machinist code to see how it all happens. I wrote that code to be read, and I love it when people get in there and have a look. :)

    RispondiElimina
  2. Oh, also worth mentioning:

    You can replace the "address { Address.make }" with just "address". Machinist will figure out that it's an association and will make an Address object for you.

    RispondiElimina
  3. FactoryGirl is better. You can define large object chains without placing the logic to build them in your tests/specs.

    https://gist.github.com/1f2dbade64a04cc205a5

    after_create, after_build, etc.

    Machinist 2 is still relatively new and doesn't support the same features as FactoryGirl.

    RispondiElimina
  4. FactoryGirl could stub your objects to not hit the database too, with Factory.stub(:person).should be_valid

    RispondiElimina
  5. @mauricioszabo: Thanks, I didn't know this. Amazing feature! Thanks for sharing :)

    RispondiElimina
  6. @vinbarnes, Object Daddy has not been updated since 2 years.

    @MetalElf0, Fabrication looks solid. Any interest to try it out?

    http://fabricationgem.org

    RispondiElimina
  7. @highflux: yeah, why not? Its syntax looks nice, and Hashrocket is a warranty of good quality, so I'll check it out in the next weeks. Expect a writeup about it! Thanks for the suggestion!

    RispondiElimina
  8. @highflux is Fabrication or machinist support after_create, after_save callbacks.

    RispondiElimina
  9. The guide for factory_girl states:

    "To not save the associated object, specify strategy: :build in the factory."

    https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md

    So just do:

    Factory.define :person do |p|
    p.name 'John'
    p.surname 'Doe'
    p.association :address, strategy: :build
    end

    RispondiElimina