作为Rails默认的测试数据生成工具Fixtures很多时候并不能满足要求。所以,基于工厂模式的众多工具纷显。其中,不乏
Factory Girl和Object Daddy这样的工具。然而,本文将介绍另外一个类似的工具Machinist,这个插件同样很有特色。
1. Machinist易于创建数据
2. 处理数据之间的关联
3. 处理和生产重复数据Sham
安装和配置
作为Rails的插件,如下安装:
./script/plugin install git://github.com/notahat/machinist.git
在spec目录下创建blueprints.rb
require File.expand_path(File.dirname(__FILE__) + "/blueprints")
当然,如果你要需要Cucumber的功能,要添加require在features/steps/env.rb
require File.join(RAILS_ROOT, 'spec', 'blueprint')
如果使用Sham的功能要修改spec_helper.rb中的
config.before(:each) { Sham.reset }
Blueprints
Machinist defines blueprints for your models. According to Pete:
A blueprint describes how to build a generic object for an ActiveRecord model. The idea is that you let the blueprint take care of constructing all the objects and attributes that you don’t care about in your test, leaving you to focus on the just the things that you’re testing.
Business.blueprint do
name { "My Company" }
address { "No.01, Down Street" }
web { "http://www.example.com" }
email { "[email protected]" }
end
Machinist will create objects by calling the save! method on the ActiveRecord model. Hence, it will throw exceptions if the validations failed. To create a new object from a blueprint, call make method on model.
business = Business.make
When testing a particular field, you could override its value by passing a parameter to make.
invalid_business = Business.make(:email => "bad@email")
Sham
Without setting values manually for attributes, you could use Machinist’s Sham class to auto-generate attribute values. Use Faker gem with Sham to easily generate the dummy values.
Here is how to define Sham methods.
Sham.name { Faker::Name.name }
Sham.business_name { Faker::Company.name }
Sham.email { Faker::Internet.email }
Sham.address { Faker::Address.street_address }
Sham.web { Faker::Internet.domain_name }
We could modify the above example of Business blueprint to use the Sham defined.
Business.blueprint do
name { Sham.business_name }
address { Sham.address }
web { Sham.web }
email { Sham.email }
end
You could generate sequences with Sham by offering a block parameter.
Sham.invoice_no {|index| "20080101-#{index}" }
Sham ensures each object created will contain unique attribute values. If you want to have duplicate values, you could pass the :unique option. For example:
Sham.coin_toss(:unique => false) { rand(2) == 0 ? 'heads' : 'tails' }
处理关联
With Machinist creating associated objects is simple. You just have to define the associated object as an attribute.
User.blueprint do
name { Sham.name }
email { Sham.email }
business
end
Further you could customize the associating object by passing attributes to make call.
User.blueprint do
name { Sham.name }
email { Sham.email }
business { Business.make(:name => "#{name} Shop") }
end
更多信息
I hope you got a basic understanding of Machinist and how it could be helpful in your tests. For more information and latest developments of Machinist, please visit its Github repo. Also, there is another good post on Machinist (with comparisons to FactoryGirl) by Tim Lucas.