用factory-girl替换fixtures来创建模拟数据
fixtures
在前面我们介绍了,rails的测试系统默认使用fixtures来创建模拟数据,这些数据以yaml的格式书写,放在db/fixtures文件夹中,每个model都有一个对应的文件,test/fixtures/users.yml。
在测试启动的时候这些fixtures中的数据会加载到测试数据库,并且加载到变量中,供单元测试和功能测试使用。
使用fixtures有几个不利的因素,使得他们处于不利的位置。
最主要的一个因素是,这些fixtures描述的数据和测试他们的行为是分开的,在不同的文件中。使用这些模拟数据,我们需要依赖于fixtures文件,这些文件很难阅读,维护不便。
假设我们需要两个user对象,用来测试我们的User.authenticate是否工作正常,我们需要编写下面的内容。
bob: username: bob email: bob@example.com password_digest: 3488f5f7efecab14b91eb96169e5e1ee518a569f password_salt: bef65e058905c379436d80d1a32e7374b139e7b0 admin: username: admin email: admin@example.com password_digest: 3488f5f7efecab14b91eb96169e5e1ee518a569f password_salt: bef65e058905c379436d80d1a32e7374b139e7b0
因为这两个数据需要存储到数据库中,我们的password_digest和password_salt需要是上面的样子,我们无法知道这两个属性的值具体代表什么意义,它们的内容到底是什么呢?
在http://guides.rubyonrails.org/testing.html的最后面的部分,推荐了一个fixtures的替代品,那就是factory girl,它还有一个rails版本factory girl rails,专门用于rails的测试。
如何在rails中使用factory girl rails
在https://github.com/thoughtbot/factory_girl/wiki有关于factory-girl使用的详细教程,基本上也适用于factory-girl-rails。
下面我们介绍一下基本的使用方法。
首先在gemfile文件中加入
gem 'factory_girl_rails'
然后执行
bundle install
然后再test目录创建factories.rb文件。这个文件的作用有点像我们使用fixtures的时候的yml文件,里面用来创建模拟数据。但是不同的是fixtures中的数据会被自动加入数据库,所以创建的时候声明的属性要和数据库匹配,是一种从数据库出发的模拟数据。但是factory-girl创建的模拟数据不会被自动加入数据库,是一种从model出发的模拟数据,所以声明的属性是和model对应的,所以不会出现使用fixtures的时候的哪种看不懂的password_digest属性值。
FactoryGirl.define do factory :user do nickname "nickname" email "ee@123.com" password "123" password_confirmation "123" end end
上面factory-girl创建了一个user对象,这个对象也同样可以在测试用使用。请注意factory :后满的内容,这样要对应于一个model的类名,第一个字母最好小写,当然大写也是可以的。
还需要在使用这些数据的地方引入一个module。假如我们想要在user的单元测试中使用factory-girl的模拟数据,可以向下面这样添加这个module。
class UserTest < ActiveSupport::TestCase include FactoryGirl::Syntax::Methods end
这样的话,我们就可以在user的单元测试中像下面这样使用这些模拟数据。
# 保存user数据到数据库 user = create(:user) # 不保存user数据,只是把它保存到user变量 user = build(:user) # 获取factory-girl中定义的user属性的键值对hash user_attributes = attributes_for(:user) # 创建一个user的stub对象 user_stub = build_stubbed(:user) # 覆盖factory-girl中user对象的部分属性 user = create(:user, first_name: 'Joe')
但是,如果我们有很多的model,都需要模拟数据,都写在factories.rb文件中,好像不太好,越写越长,而且内容混杂,也不好维护,也不利于阅读。
我们可以在创建test/factories文件夹,然后再test/factories文件夹中创建users.rb,在users.rb中写user的模拟数据。同样可以在factories文件夹中创建模拟其他model用的文件。
但是上面的factory-girl只是创建了一个user对象,如果需要多个模拟的user对象呢?可以像下面这样写,用:class => :User,来指定当前这个对象使用user的model为模板。
FactoryGirl.define do factory :user1, :class => :User do nickname "nickname" email "ee@123.com" password "123" password_confirmation "123" end factory :user2, :class => :User do nickname "nickname2" email "ee2@123.com" password "1232" password_confirmation "123" end end
上面创建了两个user对象。可以像下面这样使用它们。
def test_use_valid_user_from_factory_girl user = build(:user1) assert user.valid? end def test_use_invalid_user_from_factory_girl user = build(:user2) assert user.invalid? end
我已经在https://github.com/woaigithub/blog中加入了大量的unit test,大家可以参考,也可以提出意见,欢迎大家提意见!
本文出自 “突破中的IT结构师” 博客,请务必保留此出处http://virusswb.blog.51cto.com/115214/1076069
查看本栏目更多精彩内容:http://www.bianceng.cn/Programming/project/
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索数据模拟
, 文件
, 数据
, 对象
, setup factory
, 单元测试
, 模拟
user
rails 单元测试、android 单元测试实战、rails 实战圣经、rails实战、rails 测试,以便于您获取更多的相关知识。