# 我們與<font color=#ff7738>測試</font>的距離
---
![](https://i.imgur.com/LZF2v3I.jpg =50%x)
黃冠霖(神 Q 超人)
---
## <font color=#ff7738>為什麼</font>我們需要學<font color=#ff7738>寫測試</font>?
---
#### 看看下方的 function...
![](https://i.imgur.com/m14JatL.png)
### 什麼時候會<font color=#ff7738>改變</font>?<!-- .element: class="fragment" data-fragment-index="1" -->
## <font color=#ff7738>不知道</font><!-- .element: class="fragment" data-fragment-index="2" --><font color=#FFFFFF>,所以我們需要測試。</font><!-- .element: class="fragment" data-fragment-index="3" -->
---
## 我們總是在<font color=#ff7738>人工</font><!-- .element: class="fragment" data-fragment-index="1" -->測試
---
## <font color=#ff7738>人工</font>測試的缺點:
- 花費時間<!-- .element: class="fragment" data-fragment-index="1" --><font color=#ff7738>長</font><!-- .element: class="fragment" data-fragment-index="1" -->
- <font color=#ff7738>測試樣本不同</font>,造成測試結果可能不同<!-- .element: class="fragment" data-fragment-index="2" -->
- <font color=#ff7738>無法精準確認</font>問題在哪裡發生<!-- .element: class="fragment" data-fragment-index="3" -->
- <font color=#ff7738>受限環境</font>,無法隨時測試<!-- .element: class="fragment" data-fragment-index="4" -->
- 測試完後<font color=#ff7738>沒有任何數據報告</font>產生<!-- .element: class="fragment" data-fragment-index="5" -->
---
## <font color=#ff7738>厭倦</font>了<font color=#ff7738>一次又一次</font>的測試嗎?
### 也許<font color=#ff7738>人工</font>測試是<font color=#ff7738>必須</font>的
### 但在那<font color=#ff7738>之前</font>,我們能否<font color=#ff7738>有效減少錯誤</font>?
---
## 擁抱<font color=#ff7738>單元測試</font>吧!
### 為專案裡的<font color=#ff7738>每一單元</font>撰寫測試
### 建立<font color=#ff7738>安全</font>的防護網
<!--
逐字稿:擁抱單元測試吧!沒錯!程式裡的每一單元都是建構起整個專案的小螺絲,從底層開始,確認所有的小螺絲運作都正常,當使用它們運行專案時也不會出現較大的錯誤,如果我們在無法確認所有小螺絲都正常運作就進行人工測試的話,只是在浪費時間而已,因為你得在一個使用者的操作中反覆在程式碼中尋找細瑣的問題,也許它是個 function、甚至只可能是變數名稱打錯字,這些錯誤都不該被放大到一整個行為中,例如「註冊會員」。
-->
---
## 什麼是<font color=#ff7738>單元</font>?
### 也許你聽過...<!-- .element: class="fragment" data-fragment-index="1" -->
### 最小單位的 function 就是單元<!-- .element: class="fragment" data-fragment-index="1" -->
### 但這麼說更好...<!-- .element: class="fragment" data-fragment-index="2" -->
## 程式裡每個<font color=#ff7738>單一行為</font>,才是單元<!-- .element: class="fragment" data-fragment-index="2" -->
---
## <font color=#ff7738>單元</font>測試的優點
- 只測試單一行為,<font color=#ff7738>能夠精準</font>發現問題在哪<!-- .element: class="fragment" data-fragment-index="1" -->
- <font color=#ff7738>測試樣本相同</font>,程式邏輯不變,結果就不變<!-- .element: class="fragment" data-fragment-index="2" -->
- 想測試時<font color=#ff7738>隨時都可以</font>進行測試<!-- .element: class="fragment" data-fragment-index="3" -->
- 花費時間<!-- .element: class="fragment" data-fragment-index="4" --><font color=#ff7738>短</font><!-- .element: class="fragment" data-fragment-index="4" -->
- 測試後<font color=#ff7738>能產生測試報告</font>,作為測試指標<!-- .element: class="fragment" data-fragment-index="5" -->
---
![](https://i.imgur.com/vYS60Dq.jpg =70%x)
###### 圖片出處:[31個讓人「想檢測設計師智商多少」的糟糕飯店設計](https://www.teepr.com/1210791/jillhsiao/%E9%A3%AF%E5%BA%97%E7%B3%9F%E7%B3%95%E8%A8%AD%E8%A8%88/)
<!--點出單元測試只能夠確認每個單元都正常運作,但沒有辦法確認組合起每個正常的單元,專案就不會有問題,就是因為如此,人工測試也才是必要的,但是使用了單元測試,便可以在開發階段就先除去掉許多可能造成的 Bug,之後再來執行人工測試便輕鬆得多了。-->
---
## <font color=#ff7738>如何寫好</font>單元測試?
- 讓人對<!-- .element: class="fragment" data-fragment-index="1" --><font color=#ff7738>測試結果有信心</font><!-- .element: class="fragment" data-fragment-index="1" -->
- <font color=#ff7738>可讀</font>性<!-- .element: class="fragment" data-fragment-index="2" -->
- <font color=#ff7738>可維護</font>性<!-- .element: class="fragment" data-fragment-index="3" -->
---
## 讓人對測試結果有信心
#### 當你看見<font color=#ff7738>原本通過的測試不通過</font>時,<font color=#ff7738>不會</font>這麼說:<!-- .element: class="fragment" data-fragment-index="1" -->
### 「咦?是不是<font color=#ff7738>測試案例</font>哪裡<font color=#ff7738>有問題?</font>」<!-- .element: class="fragment" data-fragment-index="1" -->
#### 而是:<!-- .element: class="fragment" data-fragment-index="2" -->
### 「天啊!<font color=#ff7738>我</font>剛剛<font color=#ff7738>做了什麼?</font>」<!-- .element: class="fragment" data-fragment-index="2" -->
---
## 擁有可讀性的測試
### 必須擁有<font color=#ff7738>好的命名</font><!-- .element: class="fragment" data-fragment-index="1" -->以及<font color=#ff7738>好的內容</font><!-- .element: class="fragment" data-fragment-index="2" -->
---
## 好的命名,由<font color=#ff7738>三個要素</font>組成
### <font color=#ff7738>受測函式</font><!-- .element: class="fragment" data-fragment-index="1" --> <font color=#ffffff> _ </font><!-- .element: class="fragment" data-fragment-index="4" --> <font color=#ff7738>測試情境</font><!-- .element: class="fragment" data-fragment-index="2" --> <font color=#ffffff> _ </font><!-- .element: class="fragment" data-fragment-index="4" --> <font color=#ff7738>預期結果</font><!-- .element: class="fragment" data-fragment-index="3" -->
#### 例如:<!-- .element: class="fragment" data-fragment-index="5" -->
- add_UseParam1and1_Return2<!-- .element: class="fragment" data-fragment-index="5" -->
- add_UseStringParam_WillThrowError<!-- .element: class="fragment" data-fragment-index="5" -->
- add_UseOnlyOneParam_WillThrowError<!-- .element: class="fragment" data-fragment-index="5" -->
---
## <font color=#ff7738>不具體</font>的命名
- add_UseTwoNumber_ReturnSum
- add_UseWrongParam_WillThrowError
---
## 好的測試內容,能參考 <font color=#ff7738>3A 原則</font>
- Arrange:用來<font color=#ff7738>初始化受測物件</font>的過程<!-- .element: class="fragment" data-fragment-index="1" -->
- Act:<font color=#ff7738>執行受測物件</font>的方法<!-- .element: class="fragment" data-fragment-index="2" -->
- Assert:<font color=#ff7738>斷言</font>執行後的結果<!-- .element: class="fragment" data-fragment-index="3" -->
---
## 測試案例的範例(1)
![](https://i.imgur.com/aysa0iQ.png)
---
## 測試案例的範例(2)
![](https://i.imgur.com/rCg5tzN.png)
---
## <font color=#ff7738>測試案例</font>
### 可以成為
## <font color=#ff7738>工程師版本</font>的<font color=#ff7738>操作手冊</font>
---
## 擁有可維護性的測試
- <font color=#ff7738>整合</font>重複行為<!-- .element: class="fragment" data-fragment-index="1" -->
- 讓測試案例<!-- .element: class="fragment" data-fragment-index="2" --><font color=#ff7738>適應 UI 變化</font><!-- .element: class="fragment" data-fragment-index="2" -->
- 測試案例間互相<!-- .element: class="fragment" data-fragment-index="3" --><font color=#ff7738>獨立</font><!-- .element: class="fragment" data-fragment-index="3" -->
---
### 異動 `add` 拋出的錯誤訊息
![](https://i.imgur.com/rJ61ok9.jpg)
---
### 得<font color=#ff7738>修改兩個</font>測試案例,來符合函式行為
![](https://i.imgur.com/wY6jJoU.jpg)
---
### 將<font color=#ff7738>重複的部份擷取為函式</font>使用
![](https://i.imgur.com/21bV5MS.jpg =85%x)
---
## 讓測試案例適應變化
## 接下來是 <font color=#ff7738>View 的回合</font>了
---
### 在<font color=#ff7738>測試 UI </font>時...<font color=#ff7738>常</font>用 <font color=#ff7738>ClassName</font> 嗎?
## <font color=#ff7738>該是</font>使用<!-- .element: class="fragment" data-fragment-index="1" --> <font color=#ff7738>date-testid</font><!-- .element: class="fragment" data-fragment-index="1" -->
## <font color=#ff7738>解救脆弱</font>的測試案例了<!-- .element: class="fragment" data-fragment-index="1" -->
---
## 測試案例間彼此獨立
### 別讓<font color=#ff7738>自己外</font>的測試案例<!-- .element: class="fragment" data-fragment-index="1" --><font color=#ff7738>留下痕跡</font><!-- .element: class="fragment" data-fragment-index="1" -->
### 每次都應該是<!-- .element: class="fragment" data-fragment-index="2" --><font color=#ff7738>初始狀態</font><!-- .element: class="fragment" data-fragment-index="2" -->
### <font color=#ff7738>不應該讓上次</font>的狀態<font color=#ff7738>影響這次</font>的結果<!-- .element: class="fragment" data-fragment-index="2" -->
---
## 隔離環境的<font color=#ff7738>雙面刃</font> Mock
### <font color=#ff7738>善用</font> Mock 為受測函式<!-- .element: class="fragment" data-fragment-index="1" --><font color=#ff7738>隔離依賴</font><!-- .element: class="fragment" data-fragment-index="1" -->
### 讓測試<font color=#ff7738>關注點</font>停留在受測函式<!-- .element: class="fragment" data-fragment-index="1" -->
#### 但是...<!-- .element: class="fragment" data-fragment-index="2" -->
### <font color=#ff7738>濫用</font> Mock 容易<!-- .element: class="fragment" data-fragment-index="2" --><font color=#ff7738>導致無效測試</font><!-- .element: class="fragment" data-fragment-index="2" -->
---
## <font color=#ff7738>前端測試</font>會遇見的<font color=#ff7738>難點</font>
- 前端<!-- .element: class="fragment" data-fragment-index="1" --><font color=#ff7738>框架及 Library 五花八門</font><!-- .element: class="fragment" data-fragment-index="1" -->
- <font color=#ff7738>版本演進</font>速度<!-- .element: class="fragment" data-fragment-index="2" --><font color=#ff7738>太快</font><!-- .element: class="fragment" data-fragment-index="2" -->
- 書籍資料<font color=#ff7738>很難</font>找到<!-- .element: class="fragment" data-fragment-index="3" --><font color=#ff7738>深入講解前端測試</font><!-- .element: class="fragment" data-fragment-index="3" -->
---
## 如何<font color=#ff7738>開始</font>撰寫測試案例?
- 從<font color=#ff7738>簡單的函式邏輯</font>下手<!-- .element: class="fragment" data-fragment-index="1" -->
- <font color=#ff7738>歸納框架</font>的<!-- .element: class="fragment" data-fragment-index="2" --><font color=#ff7738>測試方法</font><!-- .element: class="fragment" data-fragment-index="2" -->
- <font color=#ff7738>查找並閱讀</font>生態圈的<!-- .element: class="fragment" data-fragment-index="3" --><font color=#ff7738>測試案例</font><!-- .element: class="fragment" data-fragment-index="3" -->
- <font color=#ff7738>寫就對了</font>!<!-- .element: class="fragment" data-fragment-index="4" -->
---
## <font color=#ff7738>感謝</font>大家!
{"metaMigratedAt":"2023-06-15T00:08:43.414Z","metaMigratedFrom":"YAML","title":"我們與測試的距離(簡報)","breaks":true,"contributors":"[{\"id\":\"7a2ffb80-021e-484a-b6c7-d53e707d56a1\",\"add\":12352,\"del\":2956}]"}