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

0 意見: