在上一個段落中,我們有提到需要限制 Let 的使用,然而當我們有比較複雜的測試前置條件時,就很難避免撰寫過於複雜的測試主題,此時就可以利用「前置處理」的機制來解決這個問題。
Before
Before 通常會在一個測試案例前執行,因此我們可以用來設定一些測試資料的建立。舉例來說,我們希望在一個訂單中預先加入商品,然後用來驗證這筆訂單是否符合預期,就可以使用 Before 來進行處理。
1RSpec.describe Order do
2 subject(:order) { Order.new }
3
4 before do
5 order.add_item(OrderItem.new(amount: 100))
6 order.add_item(OrderItem.new(amount: 100))
7 end
8
9 it { is_expected.to have_attributes(subtotal: 200) }
10 it { is_expected.to have_attributes(items_count: 2) }
11end
以上面的例子,我們會在開始執行 it
所給予的測試案例前,先呼叫 Order#add_item
來加入兩個金額為 100
的品項,當我們正式執行 it
來驗證時,就不會是一個什麼都沒有的 Order 物件,而是已經跟兩個 OrderItem 有所關聯的物件,因此就能夠用來驗證 #subtotal
和 #items_count
兩個方法是否正確。
After
跟 Before 不同的地方是 After 是測試案例執行結束後才被執行,通常我們會用來清理 Before 所產生的一些暫時性資料,或者將一些開關切換回去。
1RSpec.describe Worker do
2 subject(:worker) { Worker.new { true } }
3
4 describe "#execute" do
5 subject { worker.execute }
6
7 before { Worker.mode = :inline }
8 after { Worker.mode = :async }
9
10 it { is_expected.to be_truthy }
11 end
12end
Around
因為 After 很多時候都是跟著 Before 一起搭配使用,因此我們可以改用 Around 來處理,這樣在一些暫存檔案之類的處理,我們就不需要另外放一個 Let 來紀錄暫存檔案。
1RSpec.describe Parser do
2 subject(:parser) { Parser.new }
3
4 describe '#parse' do
5 subject { parser.parse }
6
7 around do |example|
8 temp_data = Tempfile.new
9 temp_data.write('{ "data": "example" }')
10 temp_data.rewind
11 parser.add(temp_data)
12
13 example.run
14
15 temp_data.unlink
16 end
17
18 it { is_expected.to include('data' => 'example')}
19 end
20end
使用 Around 的時候我們可以拿到 example
作為測試案例對應的物件,只需要在我們處理完前置條件後呼叫 example.run
就可以執行測試,並且在後續進行對測試前置處理的清理動作,可以根據情境判斷使用 Around 還是個別呼叫 Before / After 來對測試進行預先準備。
Hook Type
在預設的狀況下我們的 Hook(鉤)是針對單一測試案例的,然而有時候我們希望一次性的針對整個測試、測試群組來設定,就可以利用指定 suite
、all
的選項來設定觸發的時機點。
1RSpec.describe Worker do
2 around(:suite) do |example|
3 Worker.inline! { example.run }
4 end
5
6 context 'when worker not in parallel' do
7 before(:all) { Worker.max_job = 1 }
8
9 # ...
10 end
11end
以上面的例子,我們希望整個測試都使用 Worker.inline!
模式為前提處理,同時在特定的情況下,限制不要平行處理,這樣我們就不用在每一個測試案例都重複的呼叫這些設定變更,在測試案例非常多的狀況下,可以有效地改善執行的速度。
如果想在第一時間收到更新,歡迎訂閱弦而時習之在這系列文章更新時收到通知,如果有希望了解的知識,可以利用優雅的 RSpec 測試回饋表單告訴我。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 優雅的 RSpec 測試 - 前言
- 優雅的 RSpec 測試 - 撰寫測試的方式
- 優雅的 RSpec 測試 - RSpec 概觀
- 優雅的 RSpec 測試 - 測試案例
- 優雅的 RSpec 測試 - 組織測試
- 優雅的 RSpec 測試 - 前置處理
- 優雅的 RSpec 測試 - 常見匹配器
- 優雅的 RSpec 測試 - 內容匹配
- 優雅的 RSpec 測試 - 錯誤匹配
- 優雅的 RSpec 測試 - 共用案例
- 優雅的 RSpec 測試 - 自訂匹配器
- 優雅的 RSpec 測試 - 輔助方法
- 優雅的 RSpec 測試 - 測試替身
- 優雅的 RSpec 測試 - Mock 與 Stub
- 優雅的 RSpec 測試 - Allow 的使用方式
- 優雅的 RSpec 測試 - Allow 變化應用
- 優雅的 RSpec 測試 - Spy 的應用
- 優雅的 RSpec 測試 - 物件的可測試性
- 優雅的 RSpec 測試 - 耦合與依賴注入
- 優雅的 RSpec 測試 - 探索式的測試與重構