1. 程式人生 > >如何編寫指令碼對專案程式碼進行分析(測試篇)

如何編寫指令碼對專案程式碼進行分析(測試篇)

本篇將從一個測試的角度,對於在開發過程中,如何對程式碼進行完善的測試(包括功能以及效能的測試)。(內容屬於雜談,可能不夠嚴謹,但希望能幫到看到這篇文章的各位)

前言

我想沒有人會質疑測試的重要性,我們自己編寫的程式碼,可能需要經過很多次的測試才能上線使用。有些bug可能是微不足道的,但是有些bug則可能是致命的。要想盡早的消滅這些bug,那麼測試就成了非常重要的一環。

對於測試,有著非常多的資料,也有著非常成熟的理論體系。而且還有一種開發方式叫做“Test-Driven Development”,即“測試驅動開發”,通常也被簡稱為TDD。其大致思想是,在開發功能程式碼之前,先編寫測試的程式碼,再編寫功能程式碼,也就是所謂”測試先行”。

對於測試,也有著非常多的分類,下面是其常見的分類方式:
(1)按照是否需要執行軟體,可以分為靜態測試動態測試
(2)按照軟體開發階段,可以分為單元測試、整合測試、系統測試、驗收測試、迴歸測試等
(3)按照測試方法來分,可以分為黑盒測試白盒測試灰盒測試等。

單元測試(unittest)

本篇主要介紹的是單元測試,它是離開發人員最近的測試,這種測試通常由開發人員來完成,而不是由測試人員來完成,它通常是由開發人員來判斷自己的開發是否符合需求。

在單元測試中,如何去劃分這些“單元”是非常重要的,一般我們都會按照類裡面的方法為單位來劃分各個單元,也就是類裡面的一個方法就是一個單元,我們對它們進行逐個測試,也就是我們的單元測試。

在Python中,有數量眾多的單元測試框架和工具,比如unittest、testtools、subunit、nose、pytest等等,由於它們都是用來做單元測試的,因此它們的使用方式都是非常相似的。

我個人比較傾向於使用nose,首先,我們都知道,unittest是python提供的用於單元測試的標準模組。而nose正是基於這個模組開發出的第三方框架,並且有著更好的易用性。

使用unittest編寫測試指令碼需要將其編寫成為一個測試類,而nose不僅可以使用unittest的測試用例,並且可以支援使用函式進行測試。

至於具體如何使用nose,我就不贅述了,官方文件以及眾多的部落格資料肯定會比我寫的更加詳細。在這裡,我想說明的是:

如何編寫指令碼對專案程式碼進行分析

想要更好的瞭解如何編寫測試指令碼,我們必須明確兩點:

一、資料
測試中最麻煩的地方永遠不在於測試指令碼的編寫,而在於對於資料的準備環節,這真的是一個累人的活_(:з)∠)_
準備的資料一般可以有兩個來源:

1、來自於專案的真實資料,這類資料通常是比較可靠的(廢話),但缺點是不夠靈活。使用起來略顯麻煩。

2、自己構造,根據函式預期的功能自定義資料。優點是方便且可控,缺點是可能cover不到一些邊邊角角的地方。

那麼,我們需要準備那些資料呢?

一般來說,針對一個單元,一般是有若干個輸入;而我們也是通過函式的輸出來判斷函式功能是否達到預期的要求。

理所應當的,我們需要準備資料應該包括預期的輸入資料預期的輸出資料
而且這個資料一旦準備好了,一般是不會輕易改變的(除非是函式的功能改變了),所以,從時間點上來看:

—————————————這是時間線—————————————
  ↑                           ↑
→預期輸入A                     →預期輸入A
預期輸出B→                     預期輸出B→

看,在這條時間線上,你所準備的資料始終是不變的(或者說不能變,因為這就是判斷函式功能的依據)。隨著版本的開發,函式內部可能被重構,但是輸入和輸出的變動將會是很小的(個人見解)。

二、指令碼

資料準備好了,接下來改寫指令碼了,這裡又牽扯到一個問題,你的單元測試指令碼:
1、應該寫在哪裡?
2、data和指令碼是否應該分開。
3、你所需要測試的函式是否適合進行單元測試(個人認為比較重要)?

ok,針對上面的問題一個一個的進行分析:

首先,針對前兩個問題,亮出我的看法:你的測試指令碼應該和專案原始碼各自獨立開來。並且不應該放到離你的被測程式碼太遠的地方(方便查詢),比如,你可以把你的測試程式碼用一個test package裝起來~

理由有二:
1、方便管理,可以很方便的進行修改,而不用每次都在大段的程式碼裡定位自己的測試函式。

2、顯得有調理,一堆原始碼裡零零散散的穿插著測試程式碼,看著不揪心麼_(:з)∠)_

而第3個問題,則是針對開發環節就應該注意的問題。即程式碼的耦合性問題。
舉個例子:
當你要對使用某個框架(例如Django)開發的專案中的某個函式進行測試,你可能會遇到如下這些問題:
1、你的函式程式碼和框架的耦合性太高,直接導致你的測試指令碼無法直接呼叫這個函式。結果就是,你為了把這個函式剝離出來而不得不對其進行重構以適應單元測試的需要。(但這無法從根本解決這個問題,當函式發生改變時,你不得不重新開始構造)

2、函式中存在著過多和此次測試無關的引數或者涉及到資料庫的操作。在進行測試的環節,這些引數或者操作就是對你的阻礙。通常比較好的做法是:使用Mock,將這些無關緊要的東西用你準備好的資料遮蔽掉。從而把注意力放在你真正關心的事情上面。