SlideShare a Scribd company logo
RSpec & TDD
Tutorial
https://ihower.tw
2015/3
投影⽚片 http://ihower.tw/presentation/ihower-rspec.pdf
About me
• 張⽂文鈿 a.k.a. ihower
• http://ihower.tw
• http://twitter.com/ihower
• Instructor at ALPHA Camp
• https://alphacamp.co
• Rails Developer since 2006
• i.e. Rails 1.1.6 era
Agenda
• Part1: RSpec and TDD
• 什麼是⾃自動化測試和 RSpec
• Continuous Testing and Guard
• TDD and Code Kata
• Mocks and Stubs
• Part2: RSpec on Rails
• model, controller, view, helper, routing, mailer, request spec
• feature spec and capybara
• Tools: spring, simplecov, cucumber
• CI (Continuous Integration)
什麼是測試?
RSpec & TDD Tutorial
Sorry, I’m not QA guy :/
測試 Overview
單元測試
Unit Test
整合測試
Integration Test
驗收測試
Acceptance Test
Verification
確認程式的執⾏行結果有沒有對?
Are we writing the code right?
Validation
檢查這軟體有滿⾜足⽤用⼾戶需求嗎?
Are we writing the right software?
單元測試
Unit Test
整合測試
Integration Test
驗收測試
Acceptance Test
測試個別的類別和函式結果正確
從⽤用⼾戶觀點測試整個軟體
測試多個類別之間的互動正確
單元測試
Unit Test
整合測試
Integration Test
驗收測試
Acceptance Test
⽩白箱測試
⿊黑箱測試
單元測試
Unit Test
整合測試
Integration Test
驗收測試
Acceptance Test
Developer 開發者
QA 測試⼈人員
Verification
確認程式的執⾏行結果有沒有對?
Are we writing the code right?
我們天天都在檢查程
式的結果有沒有對
• 程式寫完後,⼿手動執⾏行看看結果對不對、
打開瀏覽器看看結果對不對? (如果你是web
developer 的話)
• 聽說有⼈人只檢查 syntax 語法沒錯就
commit 程式的?
⼿手動測試很沒效率
特別是複雜或 dependency 較多的程式,你可能會偷
懶沒測試所有的執⾏行路徑
有三種路徑,你得執⾏行(⼿手動測
試)三次才能完整檢查
def correct_year_month(year, month)
if month > 12
if month % 12 == 0
year += (month - 12) / 12
month = 12
else
year += month / 12
month = month % 12
end
end
return [year, month]
end
⽤用介⾯面⼿手動測試?
⽤用 Console 介⾯面⼿手動測?
⾃自動化測試
讓程式去測試程式
1. Instant Feedback
寫好測試後,很快就可以知道程式有沒有寫對
it "should return correct year and month" do
expect(correct_year_month(2011, 3)).to eq [2011, 3]
expect(correct_year_month(2011, 14)).to eq [2012,2]
expect(correct_year_month(2011, 24)).to eq [2012,12]
end
寫測試的時間
⼩小於
debug 除錯的時間
2. 回歸測試及重構
• 隨著程式越寫越多,新加的程式或修改,
會不會搞爛現有的功能?
• 重構的時候,會不會造成破壞?
• 如果有之前寫好的測試程式,那們就可
以幫助我們檢查。
3. 幫助你設計 API
• 寫測試的最佳時機點:先寫測試再實作
• TDD (Test-driven development)
• Red-Green-Refactor 流程
• 從呼叫者的⾓角度去看待程式,關注介⾯面,
協助設計出好⽤用的 API。
4. ⼀一種程式⽂文件
• 不知道程式的 API 怎麼呼叫使⽤用?
• 查測試程式怎麼寫的,就知道了。
⼩小結
• 你的程式不 Trivial -> 寫測試節省開發時間
• 你的程式不是⽤用過即丟 -> 回歸測試和重構
• TDD -> 設計出可測試,更好的 API 介⾯面
• API 怎麼⽤用 -> 測試也是⼀一種⽂文件
怎麼寫測試?
xUnit Framework
xUnit Framework
每個程式語⾔言都有這樣的框架
• test case 依序執⾏行各個 test :
• Setup 建⽴立初始狀態
• Exercise 執⾏行要測的程式
• Verify (assertion)驗證狀態如預期
• Teardown 結束清理資料
Ruby 的 Test::Unit
class OrderTest < Test::Unit::TestCase
def setup
@order = Order.new
end
def test_order_status_when_initialized
assert_equal @order.status, "New"
end
def test_order_amount_when_initialized
assert_equal @order.amount, 0
end
end
Method 的命名是
個⿇麻煩
describe Order do
before do
@order = Order.new
end
context "when initialized" do
it "should have default status is New" do
expect(@order.status).to eq(“New”)
end
it "should have default amount is 0" do
expect(@order.amount).to eq(0)
end
end
end
RSpec 寫法
RSpec 第⼀一印象
• 語法 Syntax 不同
• 程式更好讀
• 更像⼀一種 spec ⽂文件
RSpec
• RSpec 是⼀一種 Ruby 的測試 DSL 

(Domain-specific language)
• Semantic Code:⽐比 Test::Unit 更好讀,寫的⼈人
更容易描述測試⺫⽬目的
• Self-documenting:可執⾏行的規格⽂文件
• ⾮非常多的 Ruby on Rails 專案採⽤用 RSpec
作為測試框架
RSpec (cont.)
• 不是全新的測試⽅方法論
• 是⼀一種改良版的 xUnit Framework
• 演進⾃自 TDD,改稱 BDD (Behavior-driven
development)
• 先寫測試,後寫實作
Learn RSpec
• syntax
• syntax
• syntax
• more syntax
describe 和 context
幫助你組織分類
describe Order do
# ...
end
# 或是
describe "A Order" do
# ...
end
要測的東⻄西是什麼?
通常是⼀一個
類別
可以 Nested 加⼊入想要測試的
⽅方法是哪個
describe Order do
describe "#amount" do
# ...
end
end
通常開頭⽤用 # 表⽰示
instance method
dot 開頭表⽰示 class method
可以再 nested 加⼊入不同情境
describe Order do
describe "#amount" do
context "when user is vip" do
# ...
end
context "when user is not vip" do
# ...
end
end
end
每個 it 就是⼀一⼩小段測試
Assertions ⼜又叫作 Expectations
加⼊入 it
describe Order do
describe "#amount" do
context "when user is vip" do
it "should discount five percent if total > 1000" do
# ...
end
it "should discount ten percent if total > 10000" do
# ...
end
end
context "when user is not vip" do
it "should discount three percent if total > 10000" do
# ...
end
end
end
end
expect(…).to 或 to_not
所有物件都有這個⽅方法來定義你的期望
describe Order do
describe "#amount" do
context "when user is vip" do
it "should discount five percent if total >= 1000" do
user = User.new( :is_vip => true )
order = Order.new( :user => user, :total => 2000 )
expect(order.amount).to eq(1900)
end
it "should discount ten percent if total >= 10000" { ... }
end
context "when user is vip" { ... }
end
end
輸出結果(red)
(狀態顯⽰示為在寫 Order 主程式)
輸出結果(green)
漂亮的程式⽂文件
before 和 after
• 如同 xUnit 框架的 setup 和 teardown
• before(:each) 每段 it 之前執⾏行
• before(:all) 整段 describe 執⾏行⼀一次
• after(:each)
• afte(:all)
describe Order do
describe "#amount" do
context "when user is vip" do
before(:each) do
@user = User.new( :is_vip => true )
@order = Order.new( :user => @user )
end
it "should discount five percent if total >= 1000" do
@order.total = 2000
@order.amount.should == 1900
end
it "should discount ten percent if total >= 10000" do
@order.total = 10000
@order.amount.should == 9000
end
end
context "when user is vip" { ... }
end
end
pending
可以先列出來打算要寫的測試
describe Order do
describe "#paid?" do
it "should be false if status is new"
xit "should be true if status is paid or shipping" do
end
end
end
RSpec & TDD Tutorial
let(:name) { exp }
• 有使⽤用到才會運算(lazy),並且在同⼀一個
example 測試中多次呼叫會 Memoized 快取起
來。
• 相較於 before(:each) 可增加執⾏行速度
• 因此就不⽤用 instance variable 放 before 裡了,
增加程式可讀性
• let! 則是⾮非 lazy 版本
describe Order do
describe "#amount" do
context "when user is vip" do
let(:user) { User.new( :is_vip => true ) }
let(:order) { Order.new( :user => user ) }
it "should discount five percent if total >= 1000" do
order.total = 2000
order.amount.should == 1900
end
it "should discount ten percent if total >= 10000" do
order.total = 10000
order.amount.should == 9000
end
end
context "when user is vip" { ... }
end
end
⼀一些別名⽅方法
哪個念起來順就⽤用哪個
describe Order do # describe 和 context 其實是 alias
# it, specify, example 其實都⼀一樣
it { … }
specify { … }
example { … }
end
⼀一些慣例
• ⼀一個 rb 檔案配⼀一個同名的 _spec.rb 檔案
• 容易找
• guard 等⼯工具容易設定
• editor 有⽀支援快速鍵
• describe “#title” 是 instance method
• describe “.title” 是 class method
輸出格式
• rspec filename.rb 預設不產⽣生⽂文件
• rspec filename.rb -fd 輸出 specdoc ⽂文件
• rspec filename.rb -fh 輸出 html ⽂文件
HTML format⿎鼓勵寫出⾼高 spec coverage 程式,因為可以當做⼀一種⽂文件
Continuous Testing
• 使⽤用 guard-rspec
• 程式⼀一修改完存檔,⾃自動跑對應的測試
• 節省時間,⽴立即回饋
Code Kata
• ⼀一種練習⽅方法,透過⼩小型程式題⺫⽬目進⾏行
鍛鍊,就像學功夫套拳,重複練功⼀一樣
• 除了⾃自⼰己練,也可以 pair-programming
• TDD 需要練習才能抓到訣竅,與其說它
是⼀一種測試⽅方式,不如說它更像⼀一種設
計⼿手法
• 抓到 TDD 測試精神和訣竅,⽐比學再多漂
亮的語法糖更重要
準備 Kata 環境
https://github.com/ihower/ruby-kata
• Gemfile 設定 rspec, guard
• 安裝 growl notification (optional)
• bundle
TDD 訣竅⼀一:
Red-Green-Refactor
development cycle
FizzBuzz
• 逢三整除,輸出 Fizz
• 逢五整除,輸出 Buzz
• 逢三五整除,輸出 FizzBuzz
LeapYears
• 判斷閏年
• ⻄西元年份除以400可整除,為閏年。
• ⻄西元年份除以4可整除但除以100不可整
除,為閏年。
• 其他則是平年
RSpec & TDD Tutorial
Roman Numerals
• 轉換羅⾺馬數字
• 1 -> I
• 4 -> IV
• 5 ->V
• 9 -> IX
• 10 -> X
• 20 -> XX
What have we learned?
• ⼀一個 it 裡⾯面只有⼀一種測試⺫⽬目的,最好就
只有⼀一個 expectation
• 要先從測試 failed 失敗案例開始
• 確保每個測試都有效益,不會發⽣生砍
掉實作卻沒有造成任何測試失敗
• ⼀一開始的實作不⼀一定要先直攻⼀一般解,
可以⼀一步⼀一步在 cycle 中進⾏行思考和重構
• 測試程式碼的可讀性⽐比 DRY 更重要
• 安全重構:無論是改實作或是改測試碼,
當時的狀態應該要維持 Green
As the tests get more specific, the code
gets more generic.

Programmers make specific cases work
by writing code that makes the general
case work.
Three Laws of TDD
• ⼀一定是先寫⼀一個不通過的單元測試,才
開始實作功能
• 每次只新加⼀一個單元測試,只需要剛剛
好不通過即可,不要⼀一次加多個測試情
境
• 每次實作功能時,只需要剛剛好通過測
試即可,不多也不少
http://programmer.97things.oreilly.com/wiki/index.php/The_Three_Laws_of_Test-Driven_Development
TDD 訣竅⼆二:
讓測試引導 API 設計
Bowling Game
• 計算保齡球分數
• X (strike) 累加後兩球分數
• / (spare) 累加後⼀一球分數
BowlingGame

# roll

# roll_many(1,2,3,4)

# or roll_many(“1234512345”)

# finished? 

# score
http://www.sportcalculators.com/bowling-score-calculator
What have we learned?
• 透過寫測試,定義出哪些是類別公開的
介⾯面(API)
• 測試碼⽅方便呼叫的API,就是好API
• 不需要公開的,定義成 private ⽅方法,
讓實作有更好的物件導向封裝。
• 不需要針對 private ⽅方法直接寫單元測
試,⽽而是透過 public ⽅方法間接測試
RSpec Mocks
⽤用假的物件替換真正的物件,作為測試之⽤用
物件導向是
物件和物件之間的互動
Target
Object
Collaborator
Object
Collaborator
Object
Collaborator
Object
當你在寫⺫⽬目標類別的測試和實作
時,這些 Collaborator...
• 無法控制回傳值的外部系統 (例如第三⽅方 web service)
• 建構正確的回傳值很⿇麻煩 (例如得準備很多假資料)
• 可能很慢,拖慢測試速度 (例如耗時的運算)
• 有難以預測的回傳值 (例如亂數⽅方法)
• 還沒開始實作 (特別是採⽤用 TDD 流程)
使⽤用假物件
• 可以隔離 Collaborator 的 Dependencies
• 讓你專⼼心在⺫⽬目標類別上
• 只要 Collaborator 提供的介⾯面不變,修
改實作不會影響這邊的測試。
⽤用 double 產⽣生假物件
@user = double("user", :name => "ihower")
@user.name # "ihower"
@customer = double("customer").as_null_object
@customer.foobar # nil
測試狀態
describe "#receiver_name" do
it "should be user name" do
user = double(:user, :name => "ihower")
order = Order.new(:user => user)
expect(order.receiver_name).to eq("ihower")
end
end
測試⾏行為 Mock
如果沒被呼叫到,就算測試失敗
@gateway = double("ezcat")
# 預期等會 @gateway 必須被呼叫到 deliver ⽅方法
expect(@gateway).to receive(:deliver).with(@user).and_return(true)
# 發⽣生⾏行為,如果沒有就測試失敗
⽤用來測試⾏行為的發⽣生
describe "#ship!" do
before do
@user = double("user").as_null_object
@gateway = double("ezcat")
@order = Order.new( :user => @user, :gateway => @gateway )
end
context "with paid" do
it "should call ezship API" do
expect(@gateway).to receive(:deliver).with(@user).and_return(true)
@order.ship!
end
end
⾏行為沒發⽣生...
Partial mocking and
stubbing
• 如果 Collaborator 類別已經有了,我們可
以 reuse 它
• 只在有需要的時候 stub 或 mock 特定⽅方法
Partial Stub
可以⽤用在任意物件及類別上,假造他的⽅方法和回傳值
user = User.new
allow(user).to receive(:find).and_return("ihower")
Partial Mock
可以⽤用在任意物件及類別上,假造他的⽅方法和回傳值,

並且測試他必須被呼叫到
gateway = Gateway.new
expect(gateway).to receive(:deliver).with(user).and_return(true)
⼀一般測試流程 vs.
Mock 測試流程
Given 給定條件
When 當事情發⽣生
Then 則結果要是如何
Given 給定條件
Expect 預期會發⽣生什麼
When 當事情發⽣生
⼀一般測試是檢查物件最後的狀態
Target
Object
Collaborator
Object
Collaborator
Object
Collaborator
Object
測狀態如預期
Mocks 可以讓我們測試物件之間的⾏行為
Target
Object
Collaborator
Object
Collaborator
Object
Collaborator
Object
測這個⾏行為的發⽣生
Classical Testing v.s.
Mockist Testing
• Classical: 先決定你要完成的範圍,然後
實作這個範圍的所有物件。
• Mockist: 只針對⺫⽬目標類別做測試及實作,
不相干的⽤用假物件。
Mockist 缺點
• 你可能需要 stub 很多東⻄西,nested stub ⾮非
常不好
• stub 的回傳值可能難以建構
• 與 Collaborator 的⾏行為太耦合,改介⾯面就要
跟著改⼀一堆測試。
• 承上,即使忘了跟著改實作,單元測試還是
會過... 例如在動態語⾔言中,可能 Collaborator 後來改了⽅方法名稱,但是
這邊的測試仍然會過...
如何趨吉避凶?
• 必須擁有更⾼高層級的整合測試,使⽤用真的物
件來做測試。
• 採⽤用 TDD 思維讓 API 設計可以趨向:
• 不需要 stub 太多層
• 回傳值簡單
• 類別之間的耦合降低
• 遵守 Law of Demeter
採⽤用 TDD 並搭配
Integration Test
雖然有些 stub 和 mock
但是會設計出⽐比較好
的 API 讓副作⽤用較少
我的推論
濫⽤用 stub 和 mock
沒有⽤用 TDD,也沒有 Integration
Test
API 設計的不好,stub
的缺點就顯現出來的
我的推論
不然,請⼩小⼼心:
• ⽤用 Mocks 來完全隔離內部 Internal dependencies
• ⽤用 Mocks 來取代還沒實作的物件
版本⼀一:
這個 Order 完全隔離 Item
describe Order do
before do
@order = Order.new
end
describe "#<<" do
it "should push item into order.items" do
Item = double("Item")
item = double("item", :name => "foobar")
allow(Item).to receive(:new).and_return(item)
@order << "foobar"
expect(@order.items.last.name).to eq(“foobar”)
end
end
end
測試通過,即使還沒
實作 Item
class Order
attr_accessor :items
def initialize
self.items = []
end
def <<(item_name)
self.items << Item.new(item_name)
end
end
版本⼆二:
實作真的 Item 物件
(拿掉剛才的所有 stub code 即可)
describe Order do
before do
@order = Order.new
end
describe "#<<" do
it "should push item into order.items" do
@order << "foobar"
expect(@order.items.last.name).to eq "foobar"
end
end
end
需要寫真的 Item
讓測試通過
class Item
attr_accessor :name
def initialize(name)
self.name = name
end
end
describe Item do
it "should be created by name" do
item = Item.new("bar")
expect(item.name).to eq "bar"
end
end
差在哪? 假設我們後來
修改了 Item 的實作
class Item
attr_accessor :name
def initialize(name)
self.name = name.upcase
end
end
真的版本會有多個 Failure :/
Mocks 版本則不受影響 :)
但是如果 Item
改介⾯面呢?
class Item
attr_accessor :title
def initialize(name)
self.title = name.upcase
end
end
即使我們忘了改 Order,
Mocks 版的測試還是照過
不誤 :(
兩害相權取其輕
• 寧願看到重複原因的 Failure?
• 還是連 Failure 都捕捉不到,失去測試的意義?
So, 有限度使⽤用
• 造真物件不難的時候,造假的時間拿去造真的。
有需要再⽤用 Partial Stubbing/Mocking。

(相較於 Java,在 Ruby 裡造物件很快)
• 只在 Collaborator 不好控制的時候,Stub 它
• 只在 Collaborator 還沒實作的時候,Mock 它
• Collaborator 的狀態不好檢查或它的實作可能會
改變,這時候才改成測試⾏行為。
造假舉例:Logger
已知有⼀一個 Logger 其 log ⽅方法運作正常
# 測狀態
logger.log("Report generated")
expect(File.read("log.log")).to eq "Report generated"
# 如果 Logger 換別種實作就死了
# 測⾏行為
expect(logger).to receive(:log).with(/Report generated/)
logger.log("Report generated")
造假舉例:
MVC 中的Controller 測試
# 測狀態
it "should be created successful" do
post :create, :name => "ihower"
expect(response).to be_success
expect(User.last.name).to eq("ihower") # 會真的存進資料庫
end
# 測⾏行為
it "should be created successful" do
expect(Order).to receive(:create).with(:name => "ihower").and_return(true)
post :create, :name => "ihower"
expect(response).to be_success
end
Mocks ⼩小結
• 多⼀一種測試的⽅方法:除了已經會的測試
狀態,多了可以測試⾏行為的⽅方法
• 有需要⽤用到來讓測試更好寫,就⽤用。不
必要⽤用,就不要⽤用。
Code Kata
• Train Reservation HTTP Client library
• GET /train/{:id} 拿列⾞車座位資料
• POST /train/{:id}/reservation 定位
• Ticket Office Web Service (Part 2)
What have we learned?
• 利⽤用 Mocks 處理測試邊界(第三⽅方服務)
• 設計 Web Service API (Part 2 會繼續沿⽤用)
補充: HTTP Client 測試
• 更⼀一般性的 Mock Library https://
github.com/bblimke/webmock
• ⽤用錄的 https://github.com/vcr/vcr (for
Facebook,Twitter, Google 已經存在的服
務)
http://robots.thoughtbot.com/how-to-stub-external-services-in-tests
Reference:
• The RSpec Book
• The Rails 3 Way
• Foundation Rails 2
• xUnit Test Patterns
• everyday Rails Testing with RSpec
• http://pure-rspec-rubynation.heroku.com/
• http://jamesmead.org/talks/2007-07-09-introduction-to-mock-objects-in-ruby-at-lrug/
• http://martinfowler.com/articles/mocksArentStubs.html
• http://blog.rubybestpractices.com/posts/gregory/034-issue-5-testing-antipatterns.html
• http://blog.carbonfive.com/2011/02/11/better-mocking-in-ruby/
Thanks.

More Related Content

PDF
RSpec on Rails Tutorial
PDF
RSpec 讓你愛上寫測試
PDF
[PHP 也有 Day #64] PHP 升級指南
PDF
Ruby on Rails Presentation
PDF
Refactoring
PDF
Cypress e2e automation testing - day1 intor by: Hassan Hameed
PDF
Xpath in Selenium | Selenium Xpath Tutorial | Selenium Xpath Examples | Selen...
PDF
The lazy programmer's guide to writing thousands of tests
RSpec on Rails Tutorial
RSpec 讓你愛上寫測試
[PHP 也有 Day #64] PHP 升級指南
Ruby on Rails Presentation
Refactoring
Cypress e2e automation testing - day1 intor by: Hassan Hameed
Xpath in Selenium | Selenium Xpath Tutorial | Selenium Xpath Examples | Selen...
The lazy programmer's guide to writing thousands of tests

What's hot (20)

PDF
Code Refactoring
PPTX
Modern JS with ES6
PPTX
Integrating microservices with apache camel on kubernetes
PDF
Introduction to RxJS
PDF
Laravel Design Patterns
PDF
GraphQL Fundamentals
PPT
Class 3 - PHP Functions
PDF
Spring Boot
PDF
Typescript in React: HOW & WHY?
PDF
Applications secure by default
PDF
Spring GraphQL
PPTX
[Final] ReactJS presentation
PDF
Chapter17 of clean code
PPTX
API Testing Using REST Assured with TestNG
PPTX
Introduction to spring boot
PDF
Automated testing with Cypress
PDF
Refactoring 101
PPTX
Karate for Complex Web-Service API Testing by Peter Thomas
PPTX
Load Testing with k6 framework
PDF
REST APIs with Spring
Code Refactoring
Modern JS with ES6
Integrating microservices with apache camel on kubernetes
Introduction to RxJS
Laravel Design Patterns
GraphQL Fundamentals
Class 3 - PHP Functions
Spring Boot
Typescript in React: HOW & WHY?
Applications secure by default
Spring GraphQL
[Final] ReactJS presentation
Chapter17 of clean code
API Testing Using REST Assured with TestNG
Introduction to spring boot
Automated testing with Cypress
Refactoring 101
Karate for Complex Web-Service API Testing by Peter Thomas
Load Testing with k6 framework
REST APIs with Spring
Ad

Viewers also liked (20)

PDF
淺談 Startup 公司的軟體開發流程 v2
PDF
Cucumber on the JVM with Groovy
PDF
柴锋 跨平台移动应用的自动化验收测试
PPTX
Is Groovy better for testing than Java?
PDF
Practical Scrum with Kent Beck (SD Times Webinar)
PPTX
Between Scrum and Kanban - define a test process for Agile methodologies
PDF
教與學之間
PDF
Introduction to test_driven_development
PDF
Behavior Driven Development - How To Start with Behat
PDF
軟體品質與持續整合
PDF
RubyConf Taiwan 2011 Opening & Closing
PDF
Ruby 程式語言綜覽簡介
PDF
Yet another introduction to Git - from the bottom up
PDF
ALPHAhackathon: How to collaborate
PDF
Spock:願你的測試長長久久、生生不息
PDF
High Speed & RF Design and Layout: RFI/EMI Considerations (Design Conference ...
PDF
RubyConf Taiwan 2012 Opening & Closing
PDF
Exception Handling: Designing Robust Software in Ruby (with presentation note)
PDF
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
PDF
Exception Handling: Designing Robust Software in Ruby
淺談 Startup 公司的軟體開發流程 v2
Cucumber on the JVM with Groovy
柴锋 跨平台移动应用的自动化验收测试
Is Groovy better for testing than Java?
Practical Scrum with Kent Beck (SD Times Webinar)
Between Scrum and Kanban - define a test process for Agile methodologies
教與學之間
Introduction to test_driven_development
Behavior Driven Development - How To Start with Behat
軟體品質與持續整合
RubyConf Taiwan 2011 Opening & Closing
Ruby 程式語言綜覽簡介
Yet another introduction to Git - from the bottom up
ALPHAhackathon: How to collaborate
Spock:願你的測試長長久久、生生不息
High Speed & RF Design and Layout: RFI/EMI Considerations (Design Conference ...
RubyConf Taiwan 2012 Opening & Closing
Exception Handling: Designing Robust Software in Ruby (with presentation note)
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
Exception Handling: Designing Robust Software in Ruby
Ad

Similar to RSpec & TDD Tutorial (20)

PDF
Ruby Rails 老司機帶飛
PDF
我要活下來 - Ruby Junior 工程師的存活術
PDF
Legacy code 讀書會 1st (Ch1 - Ch5)
PPTX
PDF
Ecmascript
PDF
⼤語⾔模型 LLM 應⽤開發入⾨
PPT
Ruby 的快与慢
PDF
如何在 Java App 中導入 Scala
PDF
Linux binary Exploitation - Basic knowledge
PDF
千呼萬喚始出來的 Java SE 7
KEY
Ruby basic
PDF
网站前端代码静态检查工具研究
PPTX
Duck Typing and Multiple Inheritance
PDF
敏捷自动化测试中的教训 45min 中文
PDF
使用Dsl改善软件设计
PDF
网站前端代码静态检查工具综述
PPTX
Asp.net mvc 6 新功能初探
PPTX
JavaScript 80+ Programming and Optimization Skills
PDF
Running a Service in Production without Losing Your Sanity
PDF
模块一-Go语言特性.pdf
Ruby Rails 老司機帶飛
我要活下來 - Ruby Junior 工程師的存活術
Legacy code 讀書會 1st (Ch1 - Ch5)
Ecmascript
⼤語⾔模型 LLM 應⽤開發入⾨
Ruby 的快与慢
如何在 Java App 中導入 Scala
Linux binary Exploitation - Basic knowledge
千呼萬喚始出來的 Java SE 7
Ruby basic
网站前端代码静态检查工具研究
Duck Typing and Multiple Inheritance
敏捷自动化测试中的教训 45min 中文
使用Dsl改善软件设计
网站前端代码静态检查工具综述
Asp.net mvc 6 新功能初探
JavaScript 80+ Programming and Optimization Skills
Running a Service in Production without Losing Your Sanity
模块一-Go语言特性.pdf

More from Wen-Tien Chang (17)

PDF
評估驅動開發 Eval-Driven Development (EDD): 生成式 AI 軟體不確定性的解決方法
PDF
A brief introduction to Machine Learning
PDF
Git 版本控制系統 -- 從微觀到宏觀
PDF
從 Classes 到 Objects: 那些 OOP 教我的事
PDF
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
PDF
A brief introduction to SPDY - 邁向 HTTP/2.0
PDF
Git Tutorial 教學
PDF
那些 Functional Programming 教我的事
PDF
BDD style Unit Testing
PDF
Git and Github
PDF
Service-Oriented Design and Implement with Rails3
PDF
Rails3 changesets
PDF
遇見 Ruby on Rails
PDF
Designing Ruby APIs
PDF
Rails Security
PDF
Rails Performance
PDF
Distributed Ruby and Rails
評估驅動開發 Eval-Driven Development (EDD): 生成式 AI 軟體不確定性的解決方法
A brief introduction to Machine Learning
Git 版本控制系統 -- 從微觀到宏觀
從 Classes 到 Objects: 那些 OOP 教我的事
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to SPDY - 邁向 HTTP/2.0
Git Tutorial 教學
那些 Functional Programming 教我的事
BDD style Unit Testing
Git and Github
Service-Oriented Design and Implement with Rails3
Rails3 changesets
遇見 Ruby on Rails
Designing Ruby APIs
Rails Security
Rails Performance
Distributed Ruby and Rails

RSpec & TDD Tutorial