[活動筆記] 利用單元測試來開發『猜數字』小遊戲

前情提要

一直有在收集一些 Kata 用來練習 TDD ,
剛好台中的敏捷社群有這樣的活動, 第一時間就報名參加,
也很幸運的搶到票, 下面是我的記錄與一些心得反饋。
不過我沒有 Php 的經驗, 或許會有一些偏誤。

希望有機會可以整理出一系列的 Kata ,
讓人可以在學習 Coding 過程中將 Testing 變成一種首選(反射行為、自然反應 etc …)
可以參考我之前的Blog 從 TDD 到 TDD, Todo 到 Test 趨動開發

活動流程

  • 主持人簡單介紹, 並邀請大家輪流發言, 說明參加的目的

    這個引導技巧蠻好的, 有 Check-In 與 Warm-up 的效果
    雖然是還是有人不發言或是後續引發的討論有點少(直接用肯定句結束對話)
    但是相信多試幾次是可以改善的

  • 主講者介紹題目
  • 主講者實作題目
    • 拆分「猜數字」與「隨機數」
    • 使用 Injection 的技巧
    • 解題
  • 分組解「隨機數」
  • 主講者講解隨機數
  • 問問題

心得

看到各地開始有不同的講者來說明 Unit Test 或 TDD 感覺是很棒的,
希望能夠有更多的社群與講者來介紹. 這個工程師的基本技能

在講解的過程中, 可能是我誤會了, 但是我感覺到講者不確定是不是能講更多,
畢竟測試、單元測試(Unit Test)、測試趨動開發(TDD)的重心都有一些不同,
也許在報名前作一次篩選, 或是同時準備基本進階的教材,
Check-In 的階段, 或隨著課程進行由淺入深的介紹,
就以猜數字來說 Injection 也許可以放入進階的部份再介紹,
反而有位與會者在 Check-In 提出的問題我覺得蠻好的。

如何對猜數字這個題目, 進行需求分析, 可惜沒有進一步的研討。
第二部份的猜數字, 包含了隨機的部份, 分組討論我沒有參與到其它組別,
不太確定討論的效果為何? 但是在我的組別是有人完全不說話的,
總之線上活動與會者的參予是非常重要的,
另外在實作猜數字的測試案例時, 講者使用了我們這一組的代碼,
講者似乎有不同的看法, 它將 3 個案例合併成了 1 個,
但是在移除案例時, 並沒有實測可以保護原有案例的部份.
這裡可以處理的更細緻一些.

最後如果能有完整流程的 commits 與錄影的話更好,
當然主辦與講者可能有不同的考量就不予置評了.

用 C# 重新跑一次 Kata

我打算用 C# 重新進行一次這個 Kata 並稍作記錄

規則說明

猜數字是一個經典的遊戲, 分為出題者與答題者,
出題者必需隨機設定一組四碼不重複的數字, 答題者嚐試去猜出正確的數字,
如果答題者猜對數字且位置正確, 出題者必需給一個 A,
如果答題者猜對數字但位置不正確, 出題者必需給一個 B,
如果 4A0B 就代表答對, 遊戲結束.

設計

出題的部份, 我們可以開發給出題者輸入, 或是隨機產生題目,
隨機出題的部份我們可以拉出來當另一個功能, 所以我們先專注在猜數字的邏輯上
先是 A 的邏輯, 表示位置與數字相同, 所以我會需要定位與數字比較
B 的邏輯, 表示位置與數字相同, 這裡我會發現不存在數字比較的邏輯,
而是字串或字符的比對.
大概就這樣, 很簡單來設計我們的 Case 吧

猜數字案例

前設條件:答案為1234

  1. 5678 應該得到 0A0B : 目的是產生方法的介面與參數
  2. 1678 應該得到 1A0B : 最簡單的方式可以檢查第 1 個數字是否符合
  3. 1278 應該得到 2A0B : 最簡單的方式可以檢查第 2 個數字是否符合, 產生重複
  4. 重構 2、3 案例, 消重複使用 ACounter 作為記錄
  5. 1238 應該得到 3A0B : 目的是確定上面的重構有效
  6. 1283 應該得到 2A1B : 最簡單的方式檢查是否符合包含 3
  7. 1243 應該得到 2A2B : 最簡單的方式檢查是否符合包含 4, 產生重複
  8. 重構 6、7 案例, 消重複使用 BCounter 作為記錄
  9. 2143 應該得到 0A4B : 確認上面的重構有效

出題者的設計

這裡我覺得不適合只使用單元測試, 應該搭配整合測試可以有更好的效果

設計隨機出題

  1. 每次都是隨機的
  2. 是 4 個數字
  3. 4 個數字不重複

隨機答案案例

  1. 呼叫應得到數字 : 定義介面, 無傳入值, 回傳字串, 但是每個字元都是數字
  2. 呼叫應得到長度為 4 的字串 : 限制回傳長度
  3. 重構:使用正規表示式合併兩個 Case
  4. 4 個數字不能重複

後記

  1. 將 SetAnswer 由 public 轉為 private,內化為由程式隨機出題(也就是沒有出題者,實務上這層級的改動應參考需求)
  2. 第二層抽象, 將 SetAnswer 實作包裝一層介面, 抽象為取出不重複數字,  
    但是將字串職責留在 SetAnswer 之中
  3. 實作介面, 測試轉移到這個實作之中, 猜數字的測試改用相依性注入作 Mock
  4. C# 語言特性並沒有對集合的洗牌擴充方法, 抽出這一部份單獨實作, 並使用整合測試進行測試
  5. 改寫隨機的洗牌方法以符合 Fisher–Yates 的演算法

參考

(fin)

Please enable JavaScript to view the Gitalk. :D
Please enable JavaScript to view the LikeCoin. :P
Please enable JavaScript to view the LikeCoin. :P