Announcing rom_factory gem

It's been a while since I started using ROM and one of the things I found missing is FactoryGirl like gem for pre-populating the database with records. Of course, why not write it myself? :)

Some design decisions

While I really like FactoryGirl's DSL, I chose to deviate a little bit from the original DSL a little bit, because I wanted to avoid magic that comes with instance_eval, hence the objects are passed as arguments to a block:

RomFactory::Builder.define do |b|
  b.factory(relation: :users, name: :user) do |f|
    f.first_name "Janis"
  end
end

Note the |f| and |b|.

Another thing that is bit different from FactoryGirl is the fact that ROM does not have notion of Models and what we return is a simple RomFactory::Struct object. While I wanted to have ROM's own struct, the problem with that is that it would require ROM::Repo as a dependency, which I did not want to do just because I wanted to have a nice struct object.

Configuration

First, you have to define ROM container:

container = ROM.container(:sql, 'sqlite::memory') do |conf|
  conf.default.create_table(:users) do
    primary_key :id
    column :last_name, String, null: false
    column :first_name, String, null: false
    column :email, String, null: false
    column :created_at, Time, null: false
    column :updated_at, Time, null: false
  end
end

Once that is done, you will have to specify which container RomFactory will use:

RomFactory::Config.configure do |config|
  config.container = container
end

Simple use case

After configuration is done, you can define the factory as follows:

RomFactory::Builder.define do |b|
  b.factory(relation: :users, name: :user) do |f|
    f.first_name "Janis"
    f.last_name "Miezitis"
    f.email "janjiss@gmail.com"
  end
end

When everything is configured, you can use it in your tests as follows:

user = RomFactory::Builder.create(:user)
user.email #=> "janjiss@gmail.com"

Callable properties

You can easily define dynamic (callbale) properties if value needs to change every time it needs to be called. Anything that responds to .call can be dynamic property.

RomFactory::Builder.define do |b|
  b.factory(relation: :users, name: :user) do |f|
    f.first_name "Janis"
    f.last_name "Miezitis"
    f.email "janjiss@gmail.com"
    f.created_at {Time.now}
  end
end
user = RomFactory::Builder.create(:user)
user.created_at #=> 2016-08-27 18:17:08 -0500

Sequencing

If you want attributes to be unique each time you build a factory, you can use sequence to achieve that:

RomFactory::Builder.define do |b|
  b.factory(relation: :users, name: :user) do |f|
    f.first_name "Janis"
    f.last_name "Miezitis"
    f.sequence :email do |n|
      "janjiss#{n}@gmail.com"
    end
  end
end
user = RomFactory::Builder.create(:user)
user.email #=> janjiss1@gmail.com
user2 = RomFactory::Builder.create(:user)
user2.email #=> janjiss2@gmail.com

Enjoy :)

Janis Miezitis

Read more posts by this author.

Subscribe to Janis Miezitis personal blog

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!