Associations
有能力用原生Rspec
語法去測任何東西,一定超強的,但是為了快速了解這部分,請gem
來幫助快速完成測試。
shoulda-matchers
Github:https://github.com/thoughtbot/shoulda-matchers
官網:https://matchers.shoulda.io/
官網上示範了,有無使用此gem
需要寫的code有差多少。
安裝Gemfile
group :development, :test do
gem "shoulda-matchers"
end
#放test即可,但我還是把它跟昨天裝的gem放一起。
$ bundle install
其Github上說明,使用rails需在spec/rails_helper.rb
底下寫入此段程式。我們就先用最簡單方式處理。
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
先測一個最簡單的have_many
此文畢竟是只是分享如何使用Rspec
,就不對其他新增Class
多做處理。並省略其測試檔案。不可取的行為
$ rails g model sword --no-test-framework
$ rails db:migrate
spec/models/role_spec.rb
改下如下。
require 'rails_helper'
RSpec.describe Role, type: :model do
let(:role) { create(:role) }
describe 'associations' do
it { should have_many(:swords) }
end
describe "測試驗證功能" do
end
end
使用了shoulda-matchers
就真的只需要簡短一句it { should have_many(:swords) }
就可以檢測關聯性是否正確,但還是要說,有先了解過原本的怎麼寫會比較好。
理所當然這樣子直接檢測,只會得到一個紅燈,所以我們正確加上關聯性吧。
講個笑話:某人寫have_many(:sword),查失敗原因找了一個晚上
app/models/role.rb
class Role < ApplicationRecord
has_many :swords
end
```app/models/sword.rb`
class Sword < ApplicationRecord
belongs_to :role
end
rspec
畫面
F......
Failures:
1) Role associations is expected to have many swords
Failure/Error: it { should have_many(:swords) }
Expected Role to have a has_many association called swords (Sword does not have a role_id foreign key.)
略....
當然錯誤的,正確應該幫sword
的table
加上role_id
這個欄位,才能正確調動關聯性,所以不用擔心只有一句短短的it { should have_many(:swords) }
會讓測試水準下降。
接著完成加入欄位動作吧。
$ rails g migration add_column_swords
#migrate
class AddColumnSwords < ActiveRecord::Migration[6.1]
def change
add_column :swords , :role_id, :integer
end
end
$ rails db:migrate
rspec
畫面。
.......
Finished in 0.20472 seconds (files took 1.59 seconds to load)
7 examples, 0 failures
It work!!!!
接著秉著先寫測試再開發的原則,將我們想要建立的關聯性測試先寫上吧。spec/models/role_spec.rb
require 'rails_helper'
RSpec.describe Role, type: :model do
let(:role) { create(:role) }
describe 'associations' do
it { should have_many(:swords) }
it { should have_many(:items).through(:boxes) }
it { should belong_to(:user) }
it { should have_one(:skill) }
end
#略
end
belongs_to
第一次使用factory_bot
與shoulda
應該這邊會卡住一下下,所以先寫這個。
$ rails g model user --no-test-framework
$ rails g migration role_add_column
#migrate
class RoleAddColumn < ActiveRecord::Migration[6.1]
def change
add_column :roles, :user_id, :integer
end
end
$ rails db:migrate
User
class User < ApplicationRecord
has_one :role
end
Rolse
class Role < ApplicationRecord
belongs_to :user
#略...
end
關聯性建好了,user_id
欄位也加了,但是這樣跑rspec
一定會失敗,因為沒有建立User
物件來讓測試知道User
是不是真的有Role
,所以factory_bot
的部分也要改寫。
spec/factorise/user.rb
FactoryBot.define do
factory :user do
end
end
#這樣就可以,因為我沒有建立其他欄位。
spec/factories/role.rb
FactoryBot.define do
factory :role do
user
name { Faker::Name.first_name }
job { Faker::Job.title }
age { rand(5..130)}
end
end
#如果只想建立一個factories.rb檔案。
FactoryBot.define do
factory :user do
end
factory :role do
user
name { Faker::Name.first_name }
job { Faker::Job.title }
age { rand(5..130)}
end
end
rspec
.F.F......
Failures:
1) Role associations is expected to have many items through boxes
Failure/Error: it { should have_many(:items).through(:boxes) }
Expected Role to have a has_many association called items (no association called items)
# ./spec/models/role_spec.rb:8:in `block (3 levels) in <top (required)>
2) Role associations is expected to have one skill
Failure/Error: it { should have_one(:skill) }
Expected Role to have a has_one association called skill (no association called skill)
# ./spec/models/role_spec.rb:10:in `block (3 levels) in <top (required)>
可以發現只剩兩種關聯測試了。
接著還是將我做的事寫上,但如果關聯性很熟,可以略過了。
$ rails g model item --no-test-framework
$ rails g model box role:references item:references --no-test-framework
$ rails db:migrate
Box.Model
class Box < ApplicationRecord
belongs_to :role
belongs_to :item
end
Item.Model
class Item < ApplicationRecord
has_many :boxes
has_many :roles, through: :boxes
end
Role.Model
class Role < ApplicationRecord
has_many :boxes
has_many :items, through: :boxes
end
$ rails g model skill role_id:integer --no-test-framework
$ rails db:migrate
Skill.Model
class Skill < ApplicationRecord
belongs_to :role
end
Role.Model
class Role < ApplicationRecord
has_one :skill
end
rspec
..........
Finished in 0.2414 seconds (files took 1.69 seconds to load)
10 examples, 0 failures
雖然驗證跟關聯可能是最簡單的,測試中也是Model
最好寫,但是透過兩個方便的gem
可以讓測試更好寫~shoulda_matchers
除了關聯,驗證與contoller
都提供了更便捷的語法。
今日的內容:https://github.com/nauosika/Rspec_test/tree/D15
今天的leetcode575.Distribute Candies
題目連結:https://leetcode.com/problems/distribute-candies/
題目重點:真糖果題,會分享這題只是因為這題題目很可愛。除了看題目眼睛有點花
糖果有不同類型,1
代表1號糖果,2
代表2號糖果,以此類推。
愛麗絲能吃到最多
的量是糖果們/2
,又盡可能想吃到每種不同的糖,所以一定會吃到糖果們.uniq
。
如果今天糖果們.uniq
大於糖果們/2
,愛麗絲還是最多只能吃到糖果們/2
。
如果今天糖果們/2
大於糖果們.uniq
,愛麗絲又希望吃到糖果們.uniq
。
好可憐的愛麗絲,但是我們題目解完了。
# @param {Integer[]} candy_type
# @return {Integer}
def distribute_candies(candy_type)
[candy_type.uniq.size, candy_type.size/2].min
end
愛麗絲,多運動跟好好刷牙,就可以吃所有的糖果了。