今日繼續,由此分支內容開始。
https://github.com/nauosika/Rspec_test/tree/D_17_Rspec_content
factory_bot_rails
。增加了factory_bot_rails
於Gemfile,faker
有玩LOL的都認識,不介紹了。
group :development, :test do
#略...
gem 'factory_bot_rails', '~> 6.2'
gem 'faker', '~> 2.19'
end
官方使用手冊factory_bot_rails
https://github.com/thoughtbot/factory_bot_railsfaker
https://github.com/faker-ruby/faker
factory_bot_rails
與factory_bot
? 前者包含後者,針對Rails
integrations。
bundle
後我們需要對factory_bot_rails
做一些設定,才能讓其協助Rspec
。
一樣照著手冊新增spec/support/factory_bot.rb
。將其加入以下代碼。
require 'factory_bot' #千萬不要忘了這個
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
接著在spec/rails_helper.rb
下加入以下代碼。
require 'support/factory_bot'
到這裡算是完成第一步。
建立工廠
接著我們新增一個spec/factories
資料夾。
依照我昨天role
建立檔案。spec/factories/roles.rb
。可以只建立factories.rb
檔案,將資料都寫入其內,我沒試過,覺得有分類還是比較好。
FactoryBot.define do
factory :role do
name { "王大明" }
job { "宅男" }
age { 18 }
end
end
接著改寫spec/models/role_spec.rb
require 'rails_helper'
RSpec.describe Role, type: :model do
describe "測試驗證功能" do
context "所有欄位不能空白" do
let(:role) { create(:role) }
it "name不可以空白" do
role.name != nil
expect(role).to_not be_valid
end
it "job不可以空白" do
role.job != nil
expect(role).to_not be_valid
end
it "age不可以空白" do
role.age != nil
expect(role).to_not be_valid
end
end
end
end
我故意將=
改!=
是為了確認設定工廠是否建立成功。let(:role) { create(:role) }
主要是改寫這樣,會預設由工廠給的資料處理。let(:role) { create(:role, name: "小當家", job: "廚師", age: "20") }
也還是可以複寫參數。
rspec
畫面應該如下
FFF
Failures:
1) Role 測試驗證功能 所有欄位不能空白 name不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 82, name: "王大明", job: "宅男", age: 18, created_at: "2021-09-10 05:36:29.336135000 +0000", updated_at: "2021-09-10 05:36:29.336135000 +0000"> not to be valid
# ./spec/models/role_spec.rb:12:in `block (4 levels) in <top (required)>
2) Role 測試驗證功能 所有欄位不能空白 job不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 83, name: "王大明", job: "宅男", age: 18, created_at: "2021-09-10 05:36:29.353380000 +0000", updated_at: "2021-09-10 05:36:29.353380000 +0000"> not to be valid
# ./spec/models/role_spec.rb:17:in `block (4 levels) in <top (required)>
3) Role 測試驗證功能 所有欄位不能空白 age不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 84, name: "王大明", job: "宅男", age: 18, created_at: "2021-09-10 05:36:29.355158000 +0000", updated_at: "2021-09-10 05:36:29.355158000 +0000"> not to be valid
# ./spec/models/role_spec.rb:22:in `block (4 levels) in <top (required)>
Finished in 0.03118 seconds (files took 0.83289 seconds to load)
3 examples, 3 failures
Failed examples:
#略...
確認工廠資料都有帶入後,我們來使用faker
。
用faker
產生假資料。
將spec/factories/roles.rb
改寫如下。
Faker::Config.locale = 'zh-TW'
FactoryBot.define do
factory :role do
name { Faker::Name.first_name }
job { Faker::Job.title }
age { rand(5..130)}
end
end
正規測試應該不會去用Faker::Config.locale = 'zh-TW'
,這邊娛樂性質。稍後我就會將此行刪除。faker
支援產生中文資料沒錯,但可以產生資料有限,請見官方Githublib/locales/zh-TW.yml
,不支援中文部分還是產生英文。
跑一下rspec
應該可以看到以下類似畫面。
1) Role 測試驗證功能 所有欄位不能空白 name不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 94, name: "嘉慧", job: "Advertising Analyst", age: 116, created_at: "2021-09-10 05:53:07.818665000 +0000", updated_at: "2021-09-10 05:53:07.818665000 +0000"> not to be valid
# ./spec/models/role_spec.rb:12:in `block (4 levels) in <top (required)>
2) Role 測試驗證功能 所有欄位不能空白 job不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 95, name: "志銘", job: "IT Supervisor", age: 27, created_at: "2021-09-10 05:53:07.836171000 +0000", updated_at: "2021-09-10 05:53:07.836171000 +0000"> not to be valid
# ./spec/models/role_spec.rb:17:in `block (4 levels) in <top (required)>
3) Role 測試驗證功能 所有欄位不能空白 age不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: 96, name: "惠玲", job: "Chief Consulting Consultant", age: 115, created_at: "2021-09-10 05:53:07.838495000 +0000", updated_at: "2021-09-10 05:53:07.838495000 +0000"> not to be valid
# ./spec/models/role_spec.rb:22:in `block (4 levels) in <top (required)>
Finished in 0.18368 seconds (files took 0.84862 seconds to load)
3 examples, 3 failures
可以看到faker
生效了。
那我們再新增一些需測試的功能及將!=
改回=
。
我會順便把Faker::Config.locale = 'zh-TW'
刪除。
spec/models/role_spec.rb
目前更改為。
require 'rails_helper'
RSpec.describe Role, type: :model do
describe "測試驗證功能" do
context "欄位限制" do
let(:role) { create(:role) }
it "name不可以空白" do
role.name = nil
expect(role).to_not be_valid
end
it "job不可以空白" do
role.job = nil
expect(role).to_not be_valid
end
it "age不可以空白" do
role.age = nil
expect(role).to_not be_valid
end
it "name不能取太長" do
role.name = 'a' * 11
expect(role).to_not be_valid
end
it "job不能太短" do
role.job = 'a'
expect(role).to_not be_valid
end
it "age只能數字" do
role.age = "數字"
expect(role).to_not be_valid
end
end
end
end
app/models/role.rb
class Role < ApplicationRecord
validates :name , presence: true, length: { maximum: 10 }
validates :job , presence: true, length: { minimum: 2 }
validates :age , presence: true, numericality: { only_integer: true }
end
rspec
畫面。
......
Finished in 0.18241 seconds (files took 0.79726 seconds to load)
6 examples, 0 failures
使用factory_bot_rails
可以讓資料更多樣化,提高測試測試正確度。
今天的分支:https://github.com/nauosika/Rspec_test/tree/D_16_Rspec_content
明天透過gem
來簡化測關聯性。
今天的leetcode747. Largest Number At Least Twice of Others
題目連結:https://leetcode.com/problems/largest-number-at-least-twice-of-others/
題目重點:熟悉陣列很easy。看清楚要回傳什麼就好。
# @param {Integer[]} nums
# @return {Integer}
def dominant_index(nums)
end
puts dominant_index([3,6,1,0]) #=> 1
puts dominant_index([1,2,3,4]) #=> -1
puts dominant_index([1]) #=> 0
語法。
2.7.3 :017 > [3,6,1,0].max(2)
=> [6, 3]
那就是判斷這兩個,大的大於小的兩倍就是回傳6
在原陣列的位置。
2.7.3 :018 > [6, 3].max >= 2 * [6, 3].min
=> true
一般看到例子三就直接先想到
return 0 if nums.size == 1
解法:
def dominant_index(nums)
return 0 if nums.size == 1
max_array = nums.max(2)
max_array.max >= (max_array.min * 2) ? nums.index(max_array.max) : -1
end
可是觀察一下可以發現
2.7.3 :017 > [3,6,1,0].max(2)
=> [6, 3]
那其實可以
2.7.3 :019 > a, b = [3,6,1,0].max(2)
=> [6, 3]
2.7.3 :020 > a
=> 6
2.7.3 :021 > b
=> 3
#a永遠是最大那個。
還有
2.7.3 :022 > a, b = [1].max(2)
=> [1]
2.7.3 :023 > a
=> 1
2.7.3 :024 > b
=> nil
所以判斷式如果滿足
if b false || a > 2*b
那反而不用第一行,因為
2.7.3 :027 > a, b = [1].max(2)
=> [1]
2.7.3 :028 > [1].index(a)
=> 0
簡化:
def dominant_index(nums)
largerest, larger = nums.max(2)
!larger || largerest >= 2*larger ? nums.index(largerest) : -1
end