Letterpress is a lightweight model generator that replaces fixture files.
Add this line to your application's Gemfile:
gem 'letterpress'
And then execute:
$ bundle
Or install it yourself as:
$ gem install letterpress
-
Update Gemfile
group :development, :test do gem 'letterpress', :require => 'letterpress/rails' end
-
Install the gem
$ bundle install
-
Update config/application.rb
config.generators do |g| g.test_framework :mini_test, :spec => true, :fixture_replacement => :letterpress end
-
Generate (test|spec)/blueprint.rb file
$ rails generate letterpress:install
-
Generate a model object with its factory
$ rails generate model Comment post_id:integer body:text
-
It adds to the end of file (test|spec)/blueprint.rb
class Comment < Blueprint(ProxyMethods) default do post_id { 1 } body { "MyText" } end end
-
Modify the generated blueprint according to your preferences
class Comment < Blueprint(ProxyMethods) default do post { Post.make.new } body { "MyText" } end end
-
Write tests in test/comment_test.rb
require "minitest_helper" class CommentTest < MiniTest::Rails::Model before do @comment = Comment.make.new end it "must be valid" do @comment.valid?.must_equal true end end
Don't put the blueprint file in the support directory, if you do, the blueprint file will be required to early.
It should be placed directly in the spec folder: spec/blueprint.rb
If you do as describe below, the blueprint file is placed in the right place.
- Update config/application.rb
config.generators do |g|
g.test_framework :rspec, :fixture_replacement => :letterpress
end
- Generate spec/blueprint.rb file
rails generate letterpress:install
A blueprint for a model is defined inside the Letterpress module; the class name of the blueprint must be the same as the models class name.
Below is an example of a Letterpress User class. Letterpress has two methods for
defining blueprints: default
and define
; default
can be used once in each
class but define
can be used as many time as you like. In this example
the admin
attribute is overridden by the admin block. The admin block will inherit
the other attributes defined inside the default block.
module Letterpress
class User < Blueprint(ProxyMethods)
default do
email { "user@example.com" }
admin { false }
end
define(:admin) do
admin { true }
end
end
end
user = User.make # => returns a proxy object (an instance of Letterpress::User)
user.admin # => false; itdelegates to an instance of the User class
user.email # => "user@example.com"
user = User.make(:admin)
user.admin # => true
user.email # => "user@example.com"
user = User.make(:admin, admin: false)
user.admin # => false
user.email # => "user@example.com"
For attributes that must be unique, you can call the sn
method within the
attribute block to get a unique serial number for the object.
email { "user-#{sn}@example.com" } # Each email gets a unique serial number.
user1 = User.make
user2 = User.make
user1.email # => "user1@example.com"
user2.email # => "user2@example.com"
When you create associations you don't have to persist them inside the blueprint.
- has_many
# When defining a has_many association, you define it with an array.
# These 2 comments will only be persisted in the database when Post.make.save
# is called, and not when Post.make or Post.make.new is called.
comments { [ Comment.make.new, Comment.make.new ] }
- belongs_to
# Post.make.new defines a non persisted post instance.
# The post instance will only be saved to the database if
# Comment.make.save is called.
post { Post.make.new }
- The class methods
default
anddefine
is used for defining default attribute values. - An attribute values must be defined inside a block:
{}
. - The
sn
method is used inside an attribute block to create unique attribute values, e.g if each user instance must have a unique email address.
Letterpress ads make
to each ActiveRecord class; When make
is called on an ActiveRecord class, it returns a proxy object
that will delegate
its received messages to the ActiveRecord instance.
The proxy object implements these methods:
new
- returns the object under test or raises an exception if the object isn't valid.new!
- returns the object under test, even if not valid.save
- returns the persisted object under test or raises an exception if the object isn't valid.
User.make # Returns instance of Letterpress::User
User.make(:admin) # Returns instance of Letterpress::User
User.make(:admin, email: "foo@bar.com") # Returns instance of Letterpress::User
User.make.new # Returns a new User instance
User.make(:admin).save # Returns a persisted User instance
User.make(:admin, email: "foo@bar.com").new! # Returns a new User instance
Since each Letterpress class inherits from ProxyMethods, we can define methods in that module and they will be added to each proxy object.
In the code snippet below I have added a save_and_relod
method that will be
available on every proxy object.
module Letterpress
module ProxyMethods
def save_and_reload
record = save
@object = @object.class.find(record.id)
end
end
end
user = User.make.save_and_reload
If you want to add a method to only one proxy object, see code below.
module Letterpress
class User < Blueprint(ProxyMethods)
default do
#...
end
def password(password)
@object.password = "#{password} - in proxy"
@object
end
end
end
user = User.make.password("secret").save
user.password # => "secret - in proxy"
If you for some reason want to do something with the proxy object before returning it, you can do that, see code below.
module Letterpress
class User < Blueprint(ProxyMethods)
default do
#...
end
def self.make
user = super
# do something with the proxy object before returning it
user.password = "I always have this value"
user
end
end
end
user = User.make.new
user.password # => "I always have this value"
Ruby version 1.9.2 and 1.9.3 and Rails version 3.1
GemTesters has more information on which platforms Letterpress is tested.
gem install rubygems-test
gem test letterpress
For more info see: GemTesters
- Letterpress @ Github
- Letterpress @ GemTesters
- Letterpress @ Rubygems
- Letterpress @ Rubydoc
- Letterpress @ Travis
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request