ActiveFactory

A fixture replacement library. With it your specs will become more declarative, uniform and terse.

Feedback will be highly appreciated

Introduction

ActiveFactory allows you declaratively define which objects you want to have in a database for your spec. You can also define associations between the objects and redefine default values. Additionally ActiveFactory automatically defines accessor methods for the objects. The scope of the methods is limited to current spec. So they will not affect you other specs.

it "Task.incomplete returns only incomplete tasks" do
  models { project - tasks({:complete => 0}, {:complete => 1}) }
  project.tasks.incomplete.should == [tasks[0]]
end
it "project displays incomplete tasks" do
  models { my - project - task(:complete => 0) }
  visit project_path(project)
  page.should have_content task.title
end

These specs require the following configuration:

class ActiveFactory::Define
  factory :my, :class => User do
    username "my_name"
    password "my_password"
    before_save do
      model.save!
      context. model      
    end
  end
  factory :project do
    title { "Project #{index} title" }
    due { Time.now }
  end
  factory :task do
    title { "Task #{index} title" }
  end
end

In the configuration you specify default attribute values for an object, and in a specific test you may reassign the values for the needs of the test. Optional block after_build specifies actions that should be done after object was initialized but before saving it. If you want to create by the same factory several objects with different values, you may use blocks. Method index in those blocks returns index of the object being created.

Installation

ActiveFactory requires Rails 3 and RSpec 2.

rails plugin install git@github.com:tarasevich/active_factory.git
rails g active_factory:install

Now you are ready to add you factories spec/define_factories.rb and use models {} block in your specs.

Copyright © 2010-2011 Alexey Tarasevich, released under the MIT license

Some Examples

Consider we have factory declarations from introduction secion.

describe ProjectController do
  it "creates a new project" do
    models { my ; project_ }
    post :create, :project => project_
    Project.all.map(&:title).should == [project_[:title]]
  end
...

In previous example factory my in models block causes to emulate login. project_ declares corresponding method inside the spec. Syntax with uderscore indicates that it’s should be just hash with values taken from the factory declaration. In our case it will be {:title => "Project 0 title"}

it "modifies a project's title" do
  models { my - project }
  put :update, :id => project.id, :project => project_(:title => "New Title")
  project.reload.title.should == "New Title"
end

In this example we again use my to create a user and log in with it. Additionally we create Project instance using project factory and define method project locally for the spec. Finally we use minus sign to create association between user my and project. Active factory iterates through associations of User model and chooses the one that has Project on the other side. project_(h) is just syntax sugar for project_.merge(h)