该文章同步发布於:我的部落格
首先,我们一样先介绍基本的安装以及设定,当一切就绪的时候,写测试这件事情也就没有那麽复杂和麻烦了~
和 RSpec 一样,我们把 factory_bot_rails
放在 Gemfile:
group :development, :test do
gem 'factory_bot_rails', '~> 6.2'
end
记得,在实作专案的时候都要记得放上版本号喔!
factory_bot_rails
本身其实会根据以下的路径自动载入:
factories.rb
test/factories.rb
spec/factories.rb
factories/*.rb
test/factories/*.rb
spec/factories/*.rb
但若是你有自己想要放置的档案位置的话呢?
你可以在 config/application.rb
或是 config/envrioments.rb
中加入以下的指令:
config.factory_bot.definition_file_paths = ["你的资料夹名称/factories"]
而 factory_bot_rails
在开发环境时会自动地帮你产生工厂来产生物件,若是你觉得很烦,你想要自己建立档案的话呢?
你可以把 factory_bot_rails
移出 :development
的 group 或是在设定中加入:
config.generators do |g|
g.factory_bot false
end
接着我们还有一些基本的设定要做,我们可以开一个资料夹,路径是 spec/support/factory_bot.rb
然後在里面放入这段程序码,并确认他会被 rails_helper.rb
给 require
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
这段的目的应该不难理解,就是 include FactoryBot
的方法,让我们可以在 _spec.rb
的档案中写 FactoryBot
的方法喔!
FactoryBot
最大的目的就是制造假的实体让我们的测试可以通过,因为若是测试也需要把资料都存进资料库的话,专案完成的过程中就会浪费很多的硬碟空间,这件事情是没有必要发生的!
後面也会提到安装 Database_cleaner
在每次测试前都清空资料库确保每次的测试环境都是乾净的。
这边先示范一个最基本的制造工厂的程序码:
FactoryBot.define do
factory :user do
first_name { "John" }
last_name { "Doe" }
admin { false }
end
end
我们从第二行开始看, factory :user
的意思是,User
类别的工厂,这个 Model 有三种属性,分别是 first_name
以及 last_name
和 admin
。
这样我们就可以在写测试的时候使用:
build(:user) / create(:user)
# 这样就可以建立 user 实体,也可以把它赋予在变数里面
robert = build(:user)
# 这样他本身就会有我们在工厂里面设定好的属性!
robert.first_name # "John"
我们也可以用不同的命名,但使用同样的类别:
FactoryBot.define do
factory :admin, class: 'User' do
first_name { "John" }
last_name { "Doe" }
admin { false }
end
end
这样的话就可以这样写:
build(:admin)
除了刚刚提到基本属性的制造外,我们常常会有不能重复的属性,像是 email
这样子的属性!
这时候我们就可以使用 sequence
来制作独特的属性,使用方法是:
FactoryBot.define do
factory :user do
first_name { "John" }
last_name { "Doe" }
admin { false }
email { generate(:email) }
sequence(:email) { |n| "person#{n}@example.com" }
end
end
接着我们可以制造几个实体并且印出来看看!
person_1 = build(:user)
person_2 = build(:user)
person_1.email # "[email protected]"
person_2.email # "[email protected]"
那个 n
会自动地帮我们递增,也顺便让这个值成为 unique
,当然 sequence 有很多的特性和缩写,短短一篇文章也很难交代完整。
所以尽量以基本的使用方法来介绍~
这两种方式都可以制造出物件的实体,但最大的不同就在於有没有被 save
,那至於有没有 save
有什麽关系吗?
有的,如果没有 save
的话,在 Feature test 就会找不到画面的显示,因为该物件根本没有被储存,所以不会出现在画面上。
其实只要想像到底会不会需要物件的 id
或是关联需要 id
的?
如果需要,请用 create
来制造物件!
若是我想要一次制造很多的物件呢?
FactoryBot
也有提供了 create_list / build_list
的方法,可以这样使用:
create_list(:user, 3) # save 3 个 user
build_list(:user, 3)
至於後面的数字就是你需要几个的意思!
在写 Rails 时,我们常常会需要很多的关联,在测试时也不例外。
一开始我在学习使用 FactoryBot
的时候感到很复杂,也很困扰,但搞懂之後就觉得根本没有那麽困难~
我们先假设一间商店有很多的汉堡,这时候我们的工厂该怎麽写呢?
FactoryBot.define do
factory :burger do
association :store, factory: :store
end
end
# 也可以缩写成这样
FactoryBot.define do
factory :burger do
store
end
end
首先是 association :store
这件事,就是建立关联,接着我们告诉 FactoryBot
去哪找这个关联,factory: :store
这间工厂!
这样写的关联就是 Store has_many :burgers
的意思,因为身上会有 store_id
的表格应该是 Burger
才对!
今天的情境是,我们想要一间商店在 create
之後,就自动拥有 3 个汉堡。
一般来说在测试里面,你可能会这样写:
let(:store) { create(:store) }
before do
create(:burger, store: store)
create(:burger, store: store)
create(:burger, store: store)
end
OK,这或许没有什麽问题,也可以达到你的目的,但当测试档案变大的时候,就会很难看懂,因为太多这样的 before do end
的情形了
所以我们希望这个 store
在建立起来的时候就有汉堡了!
我们可以在工厂里面先订立好规则:
FactoryBot.define do
factory :store do
...
after :create do |store|
create_list(:burger, 3, store: store)
end
end
end
这段 Code 的意思就是在 create 的瞬间帮我产生 3 个汉堡~
这样我们就可以让 _spec.rb
的档案很乾净,很清晰!
这是我个人觉得超级好用的功能,可以让你帮同一个物件贴上不同的标签。
什麽意思呢?
假设我们的 User
有不同的角色,有管理员,有一般人,这时候原本的我会这样写:
robert = create(:user)
robert.role = "Admin"
....
利用後来覆写的方式来改变状态,但其实我们可以不用这样做,有超级方便的方法让我们来使用!
我们一样在工厂里面做好设定:
FactoryBot.define do
factory :user do
...
traits :admin do
role { 'Admin' }
end
end
end
我们可以想像在工厂里面已经有一张贴纸叫做 :admin
,接着我们可以这样用:
robert = create(:user, :admin)
robert.role # 'Admin'
是不是超级好用的,我们就可以把各式各样的 traits
先建立起来,用於应付各式各样的测试环境喔!
刚刚有提过,我们希望在每次测试的开始前都有乾净的环境可以测试,所以我们也要在环境中加入这个 Gem。
我们依照手册来安装:
# Gemfile
group :test do
gem 'database_cleaner-active_record', '~> 2.0', '>= 2.0.1'
end
一样在 spec_helper.rb
中加入:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
可以看到他在每一次的测时前都会执行这些指令唷!
关於 transaction
以及 truncation
在这个套件的差别:
transaction: rollback 的方式
truncation: 清除资料库的所有资料
FactoryBot
的使用方式实在是太多了,就像写测试一样,你问一百个人会有一百种写法~
我真的没办法一一详细介绍到每个方法,但这些方法对我来说就很够用了,甚至你也可以使用 traits
搭配 after_create hooks
来制造标签以达到很多种不一样的效果。
如果真的很闲可以看 官方文件,但我都是想到实作某种方式才去查我需要的东西。
明天会介绍另一个也很有趣的套件 Capybara ~
<<: Golang 学习笔记-- 快速上手/重点整理 - 1
今天来实作首页的活动图片轮播, 先介绍这次会用到 Vuetify 的 Carousels 组件 Ca...
Babel 为编译 ES6 的工具 那我们就要开始介绍如何安装与使用啦 https://www.np...
本篇大纲:transition( ) 移动、变换颜色、transition.delay( )、tr...
此系列文章会同步发文到个人部落格,有兴趣的读者可以前往观看喔。 测试脚本中有许多测试用例时,当需要...
工作桌会随着行业别的不同,而有不同的设置和摆放,最多的摆设就是个人电脑周边,以及电话机,还有可卸式O...