如何寫一個好的測試?總結起來就這兩點……

背景

在上一個項目上,由於項目成員大部分是新入職的同事,所以對於測試不是很熟悉,這就導致了在項目前期,項目上的很多測試都不太make sense,雖然沒有什麼定量的東西來描述,但是總結起來就2個點:

1.測試的名字比較模糊。

2.測試代碼不易讀。

深入剖析

測試名字比較模糊

對於這一個問題,是因為很多剛開始寫測試的開發腦子裡不會快就想到given、when、then這三個詞,一般我們寫測試寫得比較多的同事,都會使用should_return_xxxx_when(if)_xxxx。其實就是在腦子中想到了given、when、then。而新同事照著模仿的時候,很可能就單純地寫了should_xxx。他們只考慮了結果,但是沒有考慮條件,這就導致了讀名字還是get不到測試想要幹什麼。

對於這個問題,我想起了多年前在stackoverflow上面看到的一種寫測試名字的模板,他是這樣推薦的:

GivenA_WhenB_C,我覺得這中寫法挺好的,所以在項目中用了起來,結合實際使用,我又對此提出了兩個改進:

1.given when這兩個詞可以省略,當然前提是我們約定了最前面就是given,中間就是when,最後就是then。

通過施加規則限制來縮短測試名。

2.測試名字常常很長,一大堆駝峰其實比較不容易閱讀。所以可以使用蛇形命名法,但是這樣就需要想一個符號來分隔given、when、then了,我選擇使用___(也就是3個_),因為經過試驗,發現2個_太短了不容易一眼看出分隔

4個則又沒有必要。

最終的效果是這樣的,這是一個例子,來自我最近的訓練題:

parking_order_is_natural_order___park_cars_by_parking_assistant___car_parked_to_correct_parking_lot_in_turn

car_is_already_took___take_back_car_with_used_receipt___exception_is_thrown

parking_lot_is_available___park_a_car_by_parking_assistant___receipt_returned

car_is_parked___take_back_car_with_invalid_receipt___exception_is_thrown

這裡還有一個小技巧,如果一個測試真的沒有given的時候,或given不重要的時候,可以省略,但是___不能省略:

___xxx_xxx___xxx_xxx

可以總結一下這種命名方式的優點:

1.能制定一個規則的話,項目上的測試標題能更容易統一(可以說是統一語言了)。還可以加上靜態檢查,使得一些名字不規範的測試提前被發現

名字不規範,說明是新進項目的同事寫的,確實要重點檢查一下。

2.強制規定出given、when、then,那麼,我們在寫測試的時候,就會被強迫想清楚我們的測試要做什麼。

3.結構化的東西更適合大腦閱讀,讀測試的時候更容易,我們不需要先讀一遍測試名才能提取到given、when、then,可以一眼就定位出三個部分。

當然,也是有缺點的:

我用這種方式寫出來的測試名字一般都比較長,這個有可能是我用詞還不夠精煉,在given、when的部分可能有時候是有一部分重複的

所以也需要刻意練習,學會精簡用詞。

最後,給這種命名方式命個名吧,就叫

GWT測試命名法好了。

測試代碼不易讀

我在項目上發現,很多人習慣在構建fake數據的時候直接將所有信息屏蔽,就提供一個createX()的方法,

在createX的方法裡面可能還要構建X的構成部分:

X createX() {

Y yyy = new Y;

X xxx = new X(YYY, field1, field12);

return xxx;

}

除了createX外還有createAX、createBX,然後在不同的測試裡面混合調用。

作為看測試的我,我就很難看到到底需要一個怎樣的場景,field1到底是怎麼設置的,field2到底是怎麼設置的,而且在想改一下createX的時候,還會牽扯到其他的測試莫名其妙就掛了。

我目前使用的解決方式是這樣的:

1.先要確定好測試要涉及到的重要信息,比如上面如果field1,field2都會對測試的邏輯起到作用,

那麼,即使冗餘,也一定要寫在測試方法內。比如:

@Test

void ___xxx___xxx() {

Y y = createY();

X x = createX(field1, field12, y)

// do some thing

// assert some thing

}

這麼做的好處是,當我要看某一個測試的時候,它的前置數據我一眼就能看出來,不需要不停地command+b跟進去才知道需要什麼。

2.在應用第一條原則的時候,一定要記得,只羅列出這個測試所關心的數據。假如field3完全不參與這次

邏輯的處理,又必須要有值,那麼,在createX內部給個默認值即可,不需要放在createX參數列表中。

為什麼不適用builder?

其實之前也試過用builder,但是看起來太多了,適用create的方式能縮短要寫得代碼行數,更容易一眼看完測試。


分享到:


相關文章: