SlideShare une entreprise Scribd logo
進擊的RSpec
by Fred Hung
測試撰寫要點
測試就是規格(readable)
先寫規格-> 再寫程式碼(TDD)
測試就是要定義安全範圍
RSpec 基本寫法
describe 描述
https://www.betterspecs.org/#describe
# instance method
describe `#full_name` do
end
# class method
describe `.activated`
require `spec_helper`
describe "User" do
end
# 可以直接改成 describe User
describe User do
# described_class 就變成 User
# 會⾃動宣告⼀個
# subject { User.new}
end
subject
有⼈建議subject 要定義在⼀開始,才知道你現在是在測什麼主題
describe User do
# subject 有沒有給名字都可以
subject(:user) { User.new(first_name: 'Fred', last_name: 'Hung')}
it 'is valid' do
expect(user).to be_valid
end
# 可以直接改成
it { is_expected.to be_valid }
end
context
# 不好的寫法
it 'if user without first name it is invalid' do
end
⽤context 把情境抽出來
context 'when user without first name' do
it { is_epected.to be_invalid }
end
let
lazy load
可以nested
https://www.betterspecs.org/#let
bad
describe '#type_id' do
before { @resource = FactoryBot.create :device }
before { @type = Type.find @resource.type_id }
it 'sets the type_id field' do
expect(@resource.type_id).to eq(@type.id)
end
end
good
describe '#type_id' do
let(:resource) { FactoryBot.create :device }
let(:type) { Type.find resource.type_id }
it 'sets the type_id field' do
expect(resource.type_id).to eq(type.id)
end
end
搭配 context ,蹦出好滋味
describe User do
subject(:user) { User.new(first_name: first_name)}
let(:first_name) { 'Fred' }
context 'when user without first name' do
let(:first_name) { nil }
it { is_epected.to be_invalid }
end
end
⼀般建議pattern
1. define subject
2. set the config values
3. assert a valid state
4. mutate (context)
Hook
https://relishapp.com/rspec/rspec-core/v/3-10/docs/hooks
設定資料/ 清理
around
before
after
around
⽤法: 例如Timecop
around { |example| Timecop.freeze(Time.zone.local(2020, 12, 9), &example) }
VCR
around(:each){ |example| VCR.use_cassette("adyen/doku_indomaret_payment_method"){ example.run } }
before / after
注意lifecycle
before :suite
before :context # 這就是 :all
before :example # 這就是 :each
after :example
after :context
after :suite
# hook 可以 nested
RSpec.describe "before and after callbacks" do
before(:context) do
puts "outer before context" # 1
end
example "in outer group" do
end
after(:context) do #4
puts "outer after context"
end
describe "nested group" do
before(:context) do
puts "inner before context" #2
end
example "in nested group" do
end
after(:context) do
puts "inner after context" #3
end
end
end
before(:all) 裡⾯不能⽤ let
before == before(:each) ,每次都會執⾏⼀遍,複層scope 也會依
序執⾏⼀遍
Rubocop RSpec 建議⼀個Group 只有⼀個before / after
Matcher
就是 be eq 這種⽤來比較的運算式
常⾒的資料型態都有matcher 可以⽤
基本款 be eq (注意是否需比對物件本⾝)
be_*
Array / Hash 的比對
物件的比對
json 的比對
be_*
# 只要物件本⾝可以⽀援 xxx?
# 例如 user.admin?
# 就可以⽤ be_xxx matcher
describe User do
subject { User.new(role: role) }
let(:role) { :normal}
context 'when user role is admin' do
let(:role) { :admin }
it { is_expected.to be_admin }
end
end
Array / Hash 比對
include
contain_exactly
物件比對
Person = Struct.new(:name, :age)
person = Person.new("Jim", 32)
expect(person).to have_attributes(:name => "Jim", :age => 32)
expect(person).to have_attributes(:name => a_string_starting_with("J"), :age => (a_value > 30) )
json 比對
https://relishapp.com/waterlink/rspec-json-expectations/docs/json-
expectations
RSpec.describe "A json response" do
subject { '%{SIMPLE_JSON}' }
it "has basic info about user" do
expect(subject).to include_json(
id: 25,
email: "john.smith@example.com",
name: "John"
)
end
end
其他
shoulda_macther
DRY
share example
share context
helper
shared example
# spec/support/shared_examples/some_examples.rb
RSpec.shared_examples "some example" do |parameter|
let(:something) { parameter }
it "uses the given parameter" do
expect(something).to eq(parameter)
end
end
RSpec.describe SomeClass do
include_examples "some example", "parameter1"
# 或
it_behaves_like "some example", "parameter1"
end
shared contex
要注意,使⽤shared context 的時候該執⾏的都會被執⾏(例如有
before(:context) / before 這種)
⾃訂helper
可以寫⾃⼰的helper method
或者⾃⼰定義matcher
如果比對很複雜,可以⽤helper 增加可讀性
# spec/support/helper/some_helper.rb
# note: 通常 在 spec_helper 會 require support 下的所有東⻄
module SomeHelper
extend ActiveSupport::Concern
class_method do
# 這裡就是 extend 啦
def say_class_method
puts "class_method!!!"
end
end
# 這裡就是 include 啦
def say_helper_method
puts "helper_method!!!"
end
end
RSpec.configure do |config|
config.include SomeHelper, :say_some_module
end
測試時候可以這樣⽤
RSpec.describe FredRock, :say_some_module do
say_class_method
it "some spec" do
say_helper_method
end
end
假物件
名詞解釋
stub
假物件,假⾏為,但是不會去測他
Mock
假物件,假⾏為,會去測是否有被呼叫到
spy
假物件,去測是否有收到messages
在rspec 中使⽤要注意scope 問題
FactoryBot
https://github.com/thoughtbot/factory_bot
FactoryBot
基本寫法
nested factory
trait
initialize_with
transient
callback
沒有需要存的可以⽤ build(:some_factory)
Timecop
⽤來時空旅⾏的,要注意 travel 和 freeze 的差別
describe "some set of tests to mock" do
before do
Timecop.freeze(Time.local(1990))
end
after do
Timecop.return
end
it "should do blah blah blah" do
end
end
Database cleaner
測試的隔離策略
Base ussage
https://github.com/DatabaseCleaner/database_cleaner
DatabaseCleaner.strategy = :transaction
# 設定刪除策略
DatabaseCleaner.start # usually this is called in setup of a test
dirty_the_db
DatabaseCleaner.clean # cleanup of the test
# OR
DatabaseCleaner.cleaning do
dirty_the_db
end
Strategy
deletion : 呼叫 DELETE FROM
Truncation : 呼叫 TRUNCATE TABLE
Transaction : BEGIN TRANSACTION ROLLBACK
設定⽅式要依據情況,搭配RSepc 的Hook 使⽤
Best Practice
VCR
錄request
設定
# spec/support/vcr.rb
VCR.configure do |c|
# 指定 cassettes 位置
c.cassette_library_dir = 'vcr/cassettes'
c.hook_into :webmock
# 這⾏可以直接在 rspec 在 describe 上⽤ :vcr
c.configure_rspec_metadata!
# filter 掉 api key
c.filter_sensitive_data('<SOME_API_KEY>') { ENV['SOME_API_KEY'] }
end
使⽤
把測試案例⽤block 包起來,通常可以搭配rspec hook
around(:each){|example| VCR.use_cassette("neweb/writeoff"){ example.run }}
或是直接錄⼀個test group, 但是記得打開configure_rspec_metadata!
# 或者直接錄⼀個 group
describe '#write_off', :vcr do
end
祕技:可以在⼀個測試中使⽤多筆錄製的mock
let(:payment_to_refund_cassettes) do
[
{ name: 'google_play_receipt_cancelled' },
{ name: 'refund_shopify_order' }
]
end
it 'refund payment that receipt is canncelled' do
VCR.use_cassettes(payment_to_refund_cassettes) do
expect { subject.perform }.to change { @payment.state }.from('active').to('cancelled')
end
end
SimpleCov
測試覆蓋率
注意要放在spec helper 最上⾯
unless defined? SimpleCov
# Start SimpleCov if one is not using Spring
require 'simplecov'
SimpleCov.start 'rails'
end
跑完測試後可以去 your_repo/coverage/index.html 看
複雜的service 可以看說測試有沒有蓋到⼀些edge case
Rspec 設定
spec_helper 裡⾯很多⼤秘寶
加速測試
本地端開發
⽤spring 啟動rspec
只執⾏某⼀個測試案例(指定⾏數)
我⽤vim-rspec,其他編輯器看有沒有相關套件好⽤?
CI
Speed up rspec tests
why your spec have slowed down: 有些妙招
How I got RSpec to boot 50 times faster
加速啟動時間
補充- RSpec 寫作風格
Taming Chaotic Specs: RSpec Design Patterns by Adam Cuppy
蒼時- 針對遺留代碼加入單元測試的藝術課程⼼得
蒼時- 撰寫⼀個合適的RSpec 測試
Better Specs
ihower
討論時間

Contenu connexe

Tendances

PHP Tips for certification - OdW13
PHP Tips for certification - OdW13PHP Tips for certification - OdW13
PHP Tips for certification - OdW13
julien pauli
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
julien pauli
 

Tendances (20)

Python Compiler Internals Presentation Slides
Python Compiler Internals Presentation SlidesPython Compiler Internals Presentation Slides
Python Compiler Internals Presentation Slides
 
Objective C for Samurais
Objective C for SamuraisObjective C for Samurais
Objective C for Samurais
 
Quick tour of PHP from inside
Quick tour of PHP from insideQuick tour of PHP from inside
Quick tour of PHP from inside
 
Inside Python [OSCON 2012]
Inside Python [OSCON 2012]Inside Python [OSCON 2012]
Inside Python [OSCON 2012]
 
PHP Tips for certification - OdW13
PHP Tips for certification - OdW13PHP Tips for certification - OdW13
PHP Tips for certification - OdW13
 
Understanding PHP objects
Understanding PHP objectsUnderstanding PHP objects
Understanding PHP objects
 
How Xslate Works
How Xslate WorksHow Xslate Works
How Xslate Works
 
Create your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 VeronaCreate your own PHP extension, step by step - phpDay 2012 Verona
Create your own PHP extension, step by step - phpDay 2012 Verona
 
Embed--Basic PERL XS
Embed--Basic PERL XSEmbed--Basic PERL XS
Embed--Basic PERL XS
 
Inside PHP [OSCON 2012]
Inside PHP [OSCON 2012]Inside PHP [OSCON 2012]
Inside PHP [OSCON 2012]
 
Php and threads ZTS
Php and threads ZTSPhp and threads ZTS
Php and threads ZTS
 
Perl Moderno
Perl ModernoPerl Moderno
Perl Moderno
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
Using Jenkins for Continuous Integration of Perl components OSD2011
Using Jenkins for Continuous Integration of Perl components OSD2011 Using Jenkins for Continuous Integration of Perl components OSD2011
Using Jenkins for Continuous Integration of Perl components OSD2011
 
What's new in Perl 5.10?
What's new in Perl 5.10?What's new in Perl 5.10?
What's new in Perl 5.10?
 
PhpSpec: practical introduction
PhpSpec: practical introductionPhpSpec: practical introduction
PhpSpec: practical introduction
 
Ruby for Java Developers
Ruby for Java DevelopersRuby for Java Developers
Ruby for Java Developers
 
A(n abridged) tour of the Rust compiler [PDX-Rust March 2014]
A(n abridged) tour of the Rust compiler [PDX-Rust March 2014]A(n abridged) tour of the Rust compiler [PDX-Rust March 2014]
A(n abridged) tour of the Rust compiler [PDX-Rust March 2014]
 
Profiling php5 to php7
Profiling php5 to php7Profiling php5 to php7
Profiling php5 to php7
 
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
 

Similaire à Better rspec 進擊的 RSpec

JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
David Padbury
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琦 潘
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
Ankur Dongre
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
Ankur Dongre
 
Jsonsaga 100605143125-phpapp02
Jsonsaga 100605143125-phpapp02Jsonsaga 100605143125-phpapp02
Jsonsaga 100605143125-phpapp02
Ramamohan Chokkam
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Rails
elliando dias
 

Similaire à Better rspec 進擊的 RSpec (20)

RSpec 3.0: Under the Covers
RSpec 3.0: Under the CoversRSpec 3.0: Under the Covers
RSpec 3.0: Under the Covers
 
Introduction to unit testing
Introduction to unit testingIntroduction to unit testing
Introduction to unit testing
 
tree-sitter-objc-slides.pptx
tree-sitter-objc-slides.pptxtree-sitter-objc-slides.pptx
tree-sitter-objc-slides.pptx
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
lab4_php
lab4_phplab4_php
lab4_php
 
lab4_php
lab4_phplab4_php
lab4_php
 
TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016TDD with PhpSpec - Lone Star PHP 2016
TDD with PhpSpec - Lone Star PHP 2016
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
Jsonsaga 100605143125-phpapp02
Jsonsaga 100605143125-phpapp02Jsonsaga 100605143125-phpapp02
Jsonsaga 100605143125-phpapp02
 
JavaScript Looping Statements
JavaScript Looping StatementsJavaScript Looping Statements
JavaScript Looping Statements
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax Trees
 
Making JavaScript Libraries More Approachable
Making JavaScript Libraries More ApproachableMaking JavaScript Libraries More Approachable
Making JavaScript Libraries More Approachable
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Rails
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.ppt
 
PHP-03-Functions.ppt
PHP-03-Functions.pptPHP-03-Functions.ppt
PHP-03-Functions.ppt
 
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
 
2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Ws2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Ws
 

Dernier

JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
Max Lee
 

Dernier (20)

JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)JustNaik Solution Deck (stage bus sector)
JustNaik Solution Deck (stage bus sector)
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data Migration
 
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
 
KLARNA - Language Models and Knowledge Graphs: A Systems Approach
KLARNA -  Language Models and Knowledge Graphs: A Systems ApproachKLARNA -  Language Models and Knowledge Graphs: A Systems Approach
KLARNA - Language Models and Knowledge Graphs: A Systems Approach
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with StrimziStrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
StrimziCon 2024 - Transition to Apache Kafka on Kubernetes with Strimzi
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
GraphAware - Transforming policing with graph-based intelligence analysis
GraphAware - Transforming policing with graph-based intelligence analysisGraphAware - Transforming policing with graph-based intelligence analysis
GraphAware - Transforming policing with graph-based intelligence analysis
 
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdfA Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
A Comprehensive Appium Guide for Hybrid App Automation Testing.pdf
 
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
 
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdf
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdfImplementing KPIs and Right Metrics for Agile Delivery Teams.pdf
Implementing KPIs and Right Metrics for Agile Delivery Teams.pdf
 
Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024Top Mobile App Development Companies 2024
Top Mobile App Development Companies 2024
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Breaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfBreaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdf
 
Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM Integration
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 

Better rspec 進擊的 RSpec