2014-11-27

[讀書筆記] The pillars of good tests

[讀書筆記] The pillars of good tests

1. Writing trustworthy tests

2. Writing maintainable tests

[Maintainability]
Nonmaintainable tests are nightmares because they can ruin project schedules, or you risk losing the tests when the project is put on a more aggressive schedule.

test project 也會越來越多 如果難以維護的話
1. 會破壞Project Schedules
2. 不想再測試

2.1 Testing private or protected methods

Unit tests should be testing the public contract and public functionality of an object

應該要針對Public的來測

Solution:
(1) Making Methods Public
If a method is worth testing, it might be worth making it public, static, or at least internal, and defining a public contract against any user of it.
如果你的Method值得測試 那就將他變成Public的吧
      
(2) Extracting Methods to New Classes
如果Method包含了許多獨立的logic 就將他抽出吧

(3) Making Methods Static
如果Method沒有使用其他變數 可以考慮變成Static的

(4) Making Methods Internal
如果上述方法都失敗 有個最不推薦的方法
[InternalsVisibleTo("TestAssembly")]

Removing the method isn’t a good option because the production code uses the method too. Otherwise, there would be no reason to write the tests in the first place.

移掉Method其實不是一個好選項

2.2 Removing duplication

The “don’t repeat yourself” (DRY) principle
code有重複 就有壞味道

舉例來說:

上面看起來目前很合理
但如果寫了另一個Test

如果Production code 改變了 勢必要回來改這兩個TestMethod
導致更多的maintenance work
假設現在new完LogAnalyzer之後 要先呼叫Initialize()

那麼 我們必須在每個TestMethod裡都要加上呼叫
Initialize()的動作

Solution:
(1) Removing duplication using a helper method
透過GetNewAnalyzer()將 Initialize()封裝在這個Method
如此只要維護這裡即可

(2) Removing duplication using [SetUp]
另一種方法是寫在SetUp Method中
但是缺點就是 不是每個TestMethod都會用到這段邏輯
所以比較不推薦這種作法

2.3 Using setup methods in a maintainable manner

SetUp Method很好用 但是要注意會有以下問題:
(1) Initialize objects that are used by only some of the tests
(2) Having SETUP code that’s lengthy and hard to understand
      Refactor it

(3) Setting up fakes in the SETUP method
      要考量Fake Objects 是否每個Test Method都會用到

2.4 Enforcing test isolation

原則:
A test should always run in its own little world

如果Test Isolation沒有做好 勢必會相互影響導致錯誤的結果

以下介紹4種沒有隔離的狀況
(1) Constrained test order
      測試一定要按照某種順序
(2) Hidden test call
      在測試中呼叫其他測試
(3) Shared-state corruption
      共享的資源沒有回復
(4) External shared-state corruption       
      外部共享的資源沒有回復
Constrained test order
i. Flow Testing
   通常面對Flow Testing 會產生這種順序問題 所以一個建議的方式不要在UT中測試流程 或這是是採用Integration testing framework

ii. Laziness in cleanup
    也有可能是因為懶得清理資源 才導致必須按照某種順序來執行

Hidden test call
i. Flow Testing    
    同上

ii. Trying to remove duplication
    我們可能會為了不想要寫重複的code而在TestMethod中呼叫一個已經寫好的TestMethod 但是千萬不要這麼做

iii. Laziness in separating the tests
     別懶得抽出

Shared-state corruption


2.5 Avoiding multiple asserts

Create a separate test for each assert
Use parameterized tests
Wrap the assert call with try-catch


2.6 Avoiding testing multiple aspects of the same object

Create a full object to compare all the properties in one assertOverriding ToString(), let the test output much clearer

2.7 Avoiding overspecification in tests

OVERSPECIFY TESTS that Developers make:
Specifying purely internal behavior
Using STUBS also as MOCKS
Assuming an order or exact match when it’s not needed
xxx

3. Writing readable tests

xxx

2014-11-06

[讀書筆記] Interaction testing using mock objects

[讀書筆記] Interaction testing using mock objects

[前言]

在前一章Stubs 我們使用了Stub 來打破了Dependency
但是現實上 卻有很多的function是

沒有回傳值
沒有存狀態

針對這些Function該如何測試呢?

答案是 Mock Objects


1.1 Value-based vs. state-based vs. interaction testing



Value-based testing 
    Checks the value returned from a function.

State-based testing 
    Checks the noticeable behavior changes in the system under test, after changing its state.

Interaction testing
    Tests how an object sends input to or receives input from other objects—how that object interacts with other objects.

舉個例子:
假設有一個灌溉系統

Value-based testing 
    Check 水龍頭是否可以打開

State-based testing 
    Check 土壤濕度

Interaction testing
    在水龍頭端裝置一台監控設備 紀錄灌溉的起始結束時間以及水量 只需檢查監控設備的次數及水量是否正確

Sometimes state-based testing is the best way to go because interaction testing is too difficult to pull off.

State-based testing 有時是最好的測試方法 因為Interaction testing實在太難達到了

[Definition] 
Mock object
A mock object is a fake object in the system that decides whether the unit test has passed or failed. It does so by verifying whether the object under test interacted as expected with the fake object. There’s usually no more than one mock per test.


1.2 The difference between mocks and stubs


[Definition] 
Fake
A fake is a generic term that can be used to describe either a stub or a mock object, because they both look like the real object. Whether a fake is a stub or a mock depends on how it’s used in the current test. If it’s used to check an interaction (asserted against), it’s a mock object. Otherwise, it’s a stub.

Mocks 跟 Stubs最主要的區別如下圖:

Stub:
呼叫Assert的是 TestClass
code的例子:


Mock
用Mock Object來確認Test Pass or not


code的例子:


1.3: A simple handwritten mock example



假設新增一個需求:
當LogAnalyzer收到一個長度短於8的filename就呼叫外部WebService去記錄LogError

測試上 我們用MockWebService來替換掉外部WebService
此時我們要測的是 WebService是否確實有記錄到LogError


Why don't we write the tests directly inside the mock object code?
Reason:
1. We’d like to be able to reuse the mock object in other test cases, with other asserts on the message.
    要Reuse Mock Object

2. If the assert were put inside the mock object, whoever reads the test would have no idea what we’re asserting.
    寫在Mock裡 其他人會不知道在assert什麼


1.4 Using a mock and a stub together


假設再次新增一個需求:
如果WebService發生了Exception 系統要寄email給IT管理員

此時LogAnalyzer有兩個外部Dependence

如何測試當Exception發生時 有確實發送了Email?



Questions:

  • Why are we doing several asserts in a single test? How easy would it be to separate this test into three different tests with one assert each?Could the three asserts be combined into a single logical test?
  • It can be quite tedious to create manual mocks and stubs for each test or test class. How can we overcome that?
  • Couldn’t we have used the MockService from listing 4.1 as a stub?



1.5 One mock per test


Principle:

  • In a test where you test only one thing
  • Only one mock object in a test
  • Other fake objects are all stubs



1.6 Stub chains: stubs that produce mocks or other stubs


當一層接一層時 怎麼測試?
ex. 

你可能要寫 factory 跟 service兩個stubs
或者 Confuguration 跟 DBConfiguration兩個stubs

假如你想要替換掉 connstring
Solution:
1. 用Extract and Override    


2. 用Adapt Parameter Pattern


1.7 The problems with handwritten mocks and stubs


1. It takes time to write the mocks and stubs.

2. It’s difficult to write stubs and mocks for classes and interfaces that have many methods, properties, and events.

3. To save state for multiple calls of a mock method, you need to write a lot of boilerplate code to save the data.
<boilerplate : 照本宣科的規範;(新聞業)一成不變的陳腐文字>
為了在多次呼叫Mock Methods之後儲存狀態 需要寫很多code

4. If you want to verify all parameters on a method call, you need to write multiple asserts. If the first assert fails, the others will never run, because a failed assert throws an exception.
如果需要check 一個method的所有參數 需要多個 assert
但是只要一個assert Fail 就會中斷這次測試


5. It’s hard to reuse mock and stub code for other tests.


2014-11-03

[上課筆記] Think on your feet

Think on your feet

1. What

Think on your feet 著重的焦點是思考
能讓你迅速地理性思考 關鍵在於 "結構"

先打樁 列出要說明的Main Idea

再填入內容


2. Why

2.1 Think on your feet的好處?

幫助你思考清楚

表達想法的三個重點:

Clarity 清晰
    清楚地說明 讓人理解
Brevity 簡潔
    精準表達 
Impact 有力
    留下深刻印象

2.2 為什麼要運用計畫?

結構能讓你將一堆資訊變得井然有序
1. 集中焦點
2. 協助清晰

2.3 為什麼分成三部分?

1.說服力強
2.節奏流暢
3.印象深刻


3. How

3.1 結構格式:

    前言        
        陳述主題 宣告三個重點
        <第一印象要讓聽者牢牢記住>
        <要簡短有力>
    內文
       第一部分(結構) - 內容
       第二部分(結構) - 內容
       第三部分(結構) - 內容
    結論
       再次強調重述主題
        <最後印象要讓聽者牢牢記住>
        <要有型>
        <選出最棒的照片來定格>
        <結語要把核心主題再唸一次(但別解釋)>
        <最後讓聽者開心的笑>

3.2 6種包裝說服力的計畫

3.2.1 時鐘計畫
    用時間來安排主題
    例子: 
    早上,下午,晚上
    過去,現在,未來
    <時間的演進>
    2000年...., 2008年...., 2014年....
            
3.2.2 環球計畫
    用地理位置或是視覺位置來安排
    例子:
    台北, 台中, 台南
    住家, 公司, 公共場所
    頭, 手, 腳
    
3.2.3 三角計畫
    用不同的角度,面向或觀點來安排
    好處:
    1. 展現客觀論點
        例子:
         新產品是否成功的評估:
         技術, 行銷, 市場
    2. 顯示深思熟慮
        例子:
         創業要考慮的三個面向:
         想法, 團隊, 資金
    3. 表達各種觀點
        例子:
         教育的三種腳色:
         家長, 老師, 兒童    

3.2.4 變焦計畫
    改變觀點 用越來越廣或越來越窄的角度來安排
    越來越廣 擴大視野
    先看特定事件, 以更廣的角度來說..., 整體而言....
    越來越窄 聚焦細節
    整體而言...., 然而.... (稍微縮小範圍) , 具體而言....

    當觀點相同 採取的策略是直接認同
    當觀點不同 採取的策略是間接認同

    <或許有些人想法跟你一樣>
    <我過去的想法也跟你一樣>

    少用 <但是/可是> 帶有負面情緒
    多用 <然而/如果/同時>

3.2.5 鐘擺計畫
    描述兩邊極端立場 再轉向中間立場
    先描述完全相反的選擇 
    讓聽者趨向合理的中庸之道
    再帶領聽者往中間趨近

    激進的鐘擺 - 捍衛現狀
        讓聽者覺得兩邊極端的作法都不好 只有中庸最好
        通常答案就是維持現況
     
    溫和的鐘擺 - 折衷
        不去攻擊極端 試著在兩極之間找到平衡

3.2.6 收益計畫
    強調對聽者有益的好處
    用來宣傳, 推銷, 說服

    例子:
    推銷新東西, 你一定要告訴聽者這東西有什麼好處, 而不是提這東西有什麼特點
    <把重點放在益處>

    創造說話的動力 可以這樣安排:
    先提排名第二的功能
    再提最弱的功能
    最強的功能放在最後 塑造高潮

    反之 反收益計畫
    如果你不這樣 就會有以下缺點
    強調聽者如果不做的壞處   

3.3 讓想法更生動的作法

    圖景計畫             

             利用比喻及舉例協助聽者理解 進而記住    

    對比計畫

             利用兩種完全相反的極端來說明比較
             <後面推翻前面>
             <結局出乎意料>

   骨牌計畫

             描述因果關係:
             三因一果, 連鎖反應, 一因三果

    W5

             Who, What, Where, When, Why and How


3.4 整合

    3.4.1 銜接技巧
        肯定
             肯定對方,事實 認同對方感受
              <每個人行為的背後一定有某個"正面"的意圖>
             例子:
             我可以理解你為什麼擔心
             你提出XXX 是個很好的觀點           
        詢問
             幫助聽者組織問題
             請對方舉例
             用封閉式的問題取得資訊
        調整
             用關鍵字
             挑整層次(變廣 變窄 側面切入)
             拉回主題

    3.4.2 找出核心主題
        以聽者視角去思考主題
        1. 想想聽者的背景知識
        2. 猜測聽者的希望期待
        3. 列出聽者的擔心害怕

    3.4.3 標題
       簡短有力的標題
       用主動語氣