萬事起頭難,有些事常常是不知道怎麼開始。
Project
$ rails new project_name -T
省略原生Test
。
$ gem 'rspec-rails', :group => [:development, :test]
$ bundle
產生資源
$ rails generate rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
#一資料夾兩個檔案,一git版控檔案。
最基礎指令
$ rspec #目錄底下的測試檔一次跑。
$ rspec spec/models/????_spec.rb #指定跑單一檔。
$ rails generate --help | grep rspec #查可以幫助開哪些測試檔,看了會很後悔?
拿到任何專案,先給他rspec
啦!!!
model
開始吧。準備工作。
$ rails g model role name job age:integer
create db/migrate/20210909122636_create_roles.rb
create app/models/role.rb
invoke rspec
create spec/models/role_spec.rb
# migrate、model、spec個一。
$ rails db:create
Created database 'rspec_test_development'
Created database 'rspec_test_test'
$ rails db:migrate
== 20210909122636 CreateRoles: migrating ======================================
-- create_table(:roles)
-> 0.0084s
== 20210909122636 CreateRoles: migrated (0.0084s) =============================
確認spec/models/role_spec.rb,如未變動任何設定應該長得如下
require 'rails_helper'
RSpec.describe Role, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
pending
讓你回頭測試用,有時有些方法甚至整個想測試的單元都來不及測試,會用pending
處理。目前的寫法就是整個Class
都pending
。
單一方法需要pending
。
require 'rails_helper'
RSpec.describe Role, type: :model do
describe "#some_method" do
pending
end
end
#比較常見
RSpec.describe Role, type: :model do
pending "#some_method"
end
如果是一個方法內還有問題要處理。
RSpec.describe Role, type: :model do
describe "#some_method" do
it "計算值不能大於100" do
end
pending "常常大於100還沒處理"
end
end
這是rspec
畫面。
.* //有一個綠燈正確,因為do..end了,只是有待處理事項
Pending: (Failures listed here are expected and do not affect your suite's status)
1) Role#some_method 常常大於100還沒處理
# Not yet implemented
# ./spec/models/role_spec.rb:7
Finished in 0.00882 seconds (files took 0.74709 seconds to load)
2 examples, 0 failures, 1 pending
這篇文章我會先把pending
先移掉,網路上的教學五花八門,可能每家公司的規範也五花八門雖然我還在家裡宅不是很確定,所以看完本文還請多看文件,至少文件內用法一定正確。
先用Validations
練手一下。
以下測試單純安裝rspec-rails
而已,下篇會介紹其他輔助gem
。
require 'rails_helper'
RSpec.describe Role, type: :model do
describe "validates" do
it "name不能空白"
it "job不能塊白"
it "age不能空白"
end
end
rspec
畫面。
***
Pending: (Failures listed here are expected and do not affect your suite's status)
1) Role validates name不能空白
# Not yet implemented
# ./spec/models/role_spec.rb:5
2) Role validates job不能塊白
# Not yet implemented
# ./spec/models/role_spec.rb:6
3) Role validates age不能空白
# Not yet implemented
# ./spec/models/role_spec.rb:7
Finished in 0.0017 seconds (files took 0.77157 seconds to load)
3 examples, 0 failures, 3 pending
還是3個*
,因為我只有寫it
與期望內容,連測試物件都沒有。
修改如下
require 'rails_helper'
RSpec.describe Role, type: :model do
describe "測試驗證功能" do #能越清楚越好,英文不好所以我用中文。
context "所有欄位不能空白" do
let(:role) {Role.new} #放自己寫的`describe`外即可,此處故意放裡面。
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
一樣先看rspec
畫面
FFF
Failures:
1) Role 測試驗證功能 所有欄位不能空白 name不可以空白
Failure/Error: expect(role).to_not be_valid
expected #<Role id: nil, name: nil, job: nil, age: nil, created_at: nil, updated_at: nil> 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: nil, name: nil, job: nil, age: nil, created_at: nil, updated_at: nil> 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: nil, name: nil, job: nil, age: nil, created_at: nil, updated_at: nil> not to be valid
# ./spec/models/role_spec.rb:22:in `block (4 levels) in <top (required)>
Finished in 0.02345 seconds (files took 0.7201 seconds to load)
3 examples, 3 failures
Failed examples:
rspec ./spec/models/role_spec.rb:10 # Role 測試驗證功能 所有欄位不能空白 name不可以空白
rspec ./spec/models/role_spec.rb:15 # Role 測試驗證功能 所有欄位不能空白 job不可以空白
rspec ./spec/models/role_spec.rb:20 # Role 測試驗證功能 所有欄位不能空白 age不可以空白
三個F
,因為我還沒在`models/role.rb寫驗證。
describe
目前我是拿來描述一個大功能。context
目前我將幾種屬於同狀況的測試包在一起。
let
與before
before
寫法describe "#????" do
before(:each) do
@abc = Abc.new( #let與before都可以帶參數 )
end
end
before(:each)
每個it之前執行,可以只寫 before。before(:all)
一個RSpec.describe
只執行一次。
也有after
。after(:each)
每段it之後執行。after(:all)
一個RSpec.describe
後只執行一次。
let
let == before(:each),寫法不同外,let後面的block,會在需使用時才執行,具有lazy loading
的效果,提高測試效能,不過以會寫優先,有興趣者可以看看這篇解答:https://stackoverflow.com/questions/5974360/rspec-what-is-the-difference-between-let-and-a-before-block 目前寫短短的,不會有感覺啦XD
to
orto_not
& be_valid
be_valid
可驗證,所以to be_valid
可驗證,to_not be_valid
不可驗證。
基本語法還是請多看Rspec
的使用手冊。
我先加入Rails本身內建驗證器。
app/models/role.rb
class Role < ApplicationRecord
validates :name, presence: true
validates :job, presence: true
validates :age, presence: true
end
rspec
畫面
...
Finished in 0.0185 seconds (files took 0.77751 seconds to load)
3 examples, 0 failures
通過了!...明天介紹用Gem輔助。
今日的code。https://github.com/nauosika/Rspec_test/tree/D_17_Rspec_content
今天的leetcode.1512. Number of Good Pairs
題目連結:https://leetcode.com/problems/number-of-good-pairs/
題目重點:A pair (i, j) is called good if nums[i] == nums[j] and i < j.
想辦法紀錄這件事情發生的次數就可以了。
# @param {Integer[]} nums
# @return {Integer}
def num_identical_pairs(nums)
end
puts num_identical_pairs([1,2,3,1,1,3]) #=> 4
puts num_identical_pairs([1,1,1,1]) #=> 6
puts num_identical_pairs([1,2,3]) #=> 0
其實雙迴圈這件事總是會讓我卡住。
2.7.3 :062 > [1, 2, 3].each do |i|
2.7.3 :063 > [1, 2, 3].each do |j|
2.7.3 :064 > p [i, j]
2.7.3 :065 > end
2.7.3 :066 > end
[1, 1]
[1, 2]
[1, 3]
[2, 1]
[2, 2]
[2, 3]
[3, 1]
[3, 2]
[3, 3]
=> [1, 2, 3]
如過還記得雙迴圈那就好辦了。
def num_identical_pairs(nums)
pairs = 0
nums.each_with_index do |num1, i|
nums.each_with_index do |num2, j|
if num1 == num2 && i < j
pairs += 1
end
end
end
pairs
end
不過這題直接用times
跟for
迴圈比較更簡單明瞭。
def num_identical_pairs(nums)
pairs = 0
nums.size.times do |i|
nums.size.times do |j|
if nums[i] == nums [j] && i < j
pairs += 1
end
end
end
pairs
end
2.7.3 :067 > [1,2,3,1,1,3].size.times do |i|
2.7.3 :068 > puts i
2.7.3 :069 > end
0
1
2
3
4
5
=> 6
今天...沒有提到面試題。