申明: 本站飛宇網 https://feiyetopro.blogspot.com/。自網路收集整理之書籍、文章、影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]。謝謝!
編寫函數或類時,還可為其編寫測試。通過測試,可確定代碼面對各種輸入都能夠按要求的那樣工作。測試讓你信心滿滿,深信即便有更多的人使用你的程式,它也能正確地工作。在程式中添加新代碼時,你也可以對其進行測試,確認它們不會破壞程式既有的行為。程式師都會犯錯,因此每個程式師都必須經常測試其代碼,在用戶發現問題前找出它們。
在本章中,你將學習如何使用Python模組unittest 中的工具來測試代碼。你將學習編寫測試用例,核實一系列輸入都將得到預期的輸出。你將看到測試通過了是什麼樣子,測試未通過又是什麼樣子,還將知道測試未通過如何有助於改進代碼。你將學習如何測試函數和類,並將知道該為項目編寫多少個測試。
11.1 測試函數
要學習測試,得有要測試的代碼。下面是一個簡單的函數,它接受名和姓並返回整潔的姓名:
name_function.py
def
get_formatted_name(first, last):
"""Generate a neatly
formatted full name."""
full_name = first + ' ' + last
return full_name.title()
函數get_formatted_name() 將名和姓合併成姓名,在名和姓之間加上一個空格,並將它們的首字母都大寫,再返回結果。為核實get_formatted_name() 像期望的那樣工作,我們來編寫一個使用這個函數的程式。程式names.py讓使用者輸入名和姓,並顯示整潔的全名:
names.py
from
name_function import get_formatted_name
print("Enter
'q' at any time to quit.")
while
True:
first = input("\nPlease give me a first
name: ")
if first == 'q':
break
last = input("Please give me a last
name: ")
if last == 'q':
break
formatted_name = get_formatted_name(first,
last)
print("\tNeatly formatted name: "
+ formatted_name + '.')
這個程式從name_function.py中導入get_formatted_name() 。用戶可輸入一系列的名和姓,並看到格式整潔的全名:
Enter
'q' at any time to quit.
Please
give me a first name: janis
Please
give me a last name: joplin
Neatly formatted name: Janis Joplin.
Please
give me a first name: bob
Please
give me a last name: dylan
Neatly formatted name: Bob Dylan.
Please
give me a first name: q
從上述輸出可知,合併得到的姓名正確無誤。現在假設我們要修改get_formatted_name() ,使其還能夠處理中間名。這樣做時,我們要確保不破壞這個函數處理只有名和姓的姓名的方式。為此,我們可以在每次修改get_formatted_name() 後都進行測試:運行程式names.py,並輸入像Janis Joplin 這樣的姓名,但這太煩瑣了。所幸Python提供了一種自動測試函數輸出的高效方式。倘若我們對get_formatted_name() 進行自動測試,就能始終信心滿滿,確信給這個函數提供我們測試過的姓名時,它都能正確地工作。
11.1.1 單元測試和測試用例
Python標準庫中的模組unittest 提供了代碼測試工具。單元測試 用於核實函數的某個方面沒有問題;測試用例 是一組單元測試,這些單元測試一起核實函數在各種情形下的行為都符合要求。良好的測試用例考慮到了函數可能收到的各種輸入,包含針對所有這些情形的測試。全覆蓋式測試 用例包含一整套單元測試,涵蓋了各種可能的函數使用方式。對於大型項目,要實現全覆蓋可能很難。通常,最初只要針對代碼的重要行為編寫測試即可,等項目被廣泛使用時再考慮全覆蓋。
11.1.2 可通過的測試
創建測試用例的語法需要一段時間才能習慣,但測試用例創建後,再添加針對函數的單元測試就很簡單了。要為函數編寫測試用例,可先導入模組unittest 以及要測試的函數,再創建一個繼承unittest.TestCase 的類,並編寫一系列方法對函數行為的不同方面進行測試。
下面是一個隻包含一個方法的測試用例,它檢查函數get_formatted_name() 在給定名和姓時能否正確地工作:
test_name_function.py
import unittest
from name_function import get_formatted_name
❶ class
NamesTestCase(unittest.TestCase):
"""測試name_function.py"""
def test_first_last_name(self):
"""能夠正確地處理像Janis
Joplin這樣的姓名嗎?"""
❷ formatted_name = get_formatted_name('janis',
'joplin')
❸ self.assertEqual(formatted_name,
'Janis Joplin')
unittest.main()
首先,我們導入了模組unittest 和要測試的函數get_formatted_name() 。在❶處,我們創建了一個名為NamesTestCase 的類,用於包含一系列針對get_formatted_name() 的單元測試。你可隨便給這個類命名,但最好讓它看起來與要測試的函數相關,並包含字樣Test。這個類必須繼承unittest.TestCase 類,這樣Python才知道如何運行你編寫的測試。
NamesTestCase 只包含一個方法,用於測試get_formatted_name() 的一個方面。我們將這個方法命名為test_first_last_name() ,因為我們要核實的是只有名和姓的姓名能否被正確地格式化。我們運行testname_function.py時,所有以test 打頭的方法都將自動運行。在這個方法中,我們調用了要測試的函數,並存儲了要測試的返回值。在這個示例中,我們使用實參'janis' 和'joplin' 調用get_formatted_name() ,並將結果存儲到變數formatted_name 中(見❷)。
在❸處,我們使用了unittest 類最有用的功能之一:一個斷言 方法。斷言方法用來核實得到的結果是否與期望的結果一致。在這裡,我們知道get_formatted_name() 應返回這樣的姓名,即名和姓的首字母為大寫,且它們之間有一個空格,因此我們期望formatted_name 的值為Janis Joplin 。為檢查是否確實如此,我們調用unittest 的方法assertEqual() ,並向它傳遞formatted_name 和'Janis Joplin' 。代碼行self.assertEqual(formatted_name,
'Janis Joplin') 的意思是說:“將formatted_name 的值同字串'Janis
Joplin' 進行比較,如果它們相等,就萬事大吉,如果它們不相等,跟我說一聲!”
代碼行unittest.main() 讓Python運行這個檔中的測試。運行test_name_function.py時,得到的輸出如下:
.
----------------------------------------------------------------------
Ran 1
test in 0.000s
OK
第1行的句點表明有一個測試通過了。接下來的一行指出Python運行了一個測試,消耗的時間不到0.001秒。最後的OK 表明該測試用例中的所有單元測試都通過了。
上述輸出表明,給定包含名和姓的姓名時,函數get_formatted_name() 總是能正確地處理。修改get_formatted_name() 後,可再次運行這個測試用例。如果它通過了,我們就知道在給定Janis
Joplin 這樣的姓名時,這個函數依然能夠正確地處理。
11.1.3 不能通過的測試
測試未通過時結果是什麼樣的呢?我們來修改get_formatted_name() ,使其能夠處理中間名,但這樣做時,故意讓這個函數無法正確地處理像Janis Joplin這樣只有名和姓的姓名。
下面是函數get_formatted_name() 的新版本,它要求通過一個實參指定中間名:
name_function.py
def
get_formatted_name(first, middle, last):
"""生成整潔的姓名"""
full_name = first + ' ' + middle + ' ' +
last
return full_name.title()
這個版本應該能夠正確地處理包含中間名的姓名,但對其進行測試時,我們發現它再也不能正確地處理只有名和姓的姓名。這次運行程式test_name_function.py時,輸出如下:
❶ E
======================================================================
❷ ERROR:
test_first_last_name (__main__.NamesTestCase)
----------------------------------------------------------------------
❸ Traceback
(most recent call last):
File "test_name_function.py",
line 8, in test_first_last_name
formatted_name =
get_formatted_name('janis', 'joplin')
TypeError: get_formatted_name() missing 1
required positional argument: 'last'
----------------------------------------------------------------------
❹ Ran 1
test in 0.000s
❺ FAILED
(errors=1)
其中包含的資訊很多,因為測試未通過時,需要讓你知道的事情可能有很多。第1行輸出只有一個字母E (見❶),它指出測試用例中有一個單元測試導致了錯誤。接下來,我們看到NamesTestCase 中的test_first_last_name() 導致了錯誤(見❷)。測試用例包含眾多單元測試時,知道哪個測試未通過至關重要。在❸處,我們看到了一個標準的traceback,它指出函式呼叫get_formatted_name('janis', 'joplin') 有問題,因為它缺少一個必不可少的位置實參。
我們還看到運行了一個單元測試(見❹)。最後,還看到了一條消息,它指出整個測試用例都未通過,因為運行該測試用例時發生了一個錯誤(見❺)。這條消息位於輸出末尾,讓你一眼就能看到——你可不希望為獲悉有多少測試未通過而翻閱長長的輸出。
11.1.4 測試未通過時怎麼辦
測試未通過時怎麼辦呢?如果你檢查的條件沒錯,測試通過了意味著函數的行為是對的,而測試未通過意味著你編寫的新代碼有錯。因此,測試未通過時,不要修改測試,而應修復導致測試不能通過的代碼:檢查剛對函數所做的修改,找出導致函數行為不符合預期的修改。
在這個示例中,get_formatted_name() 以前只需要兩個實參——名和姓,但現在它要求提供名、中間名和姓。新增的中間名參數是必不可少的,這導致get_formatted_name() 的行為不符合預期。就這裡而言,最佳的選擇是讓中間名變為可選的。這樣做後,使用類似於Janis Joplin的姓名進行測試時,測試就會通過了,同時這個函數還能接受中間名。下面來修改get_formatted_name() ,將中間名設置為可選的,然後再次運行這個測試用例。如果通過了,我們接著確認這個函數能夠妥善地處理中間名。
要將中間名設置為可選的,可在函式定義中將形參middle 移到形參列表末尾,並將其預設值指定為一個空字串。我們還要添加一個if 測試,以便根據是否提供了中間名相應地創建姓名:
name_function.py
def
get_formatted_name(first, last, middle=''):
"""生成整潔的姓名"""
if middle:
full_name = first + ' ' + middle + ' '
+ last
else:
full_name = first + ' ' + last
return full_name.title()
在get_formatted_name() 的這個新版本中,中間名是可選的。如果向這個函數傳遞了中間名(if middle: ),姓名將包含名、中間名和姓,否則姓名將只包含名和姓。現在,對於兩種不同的姓名,這個函數都應該能夠正確地處理。為確定這個函數依然能夠正確地處理像Janis Joplin這樣的姓名,我們再次運行test_name_function.py:
.
----------------------------------------------------------------------
Ran 1
test in 0.000s
OK
現在,測試用例通過了。太好了,這意味著這個函數又能正確地處理像Janis Joplin這樣的姓名了,而且我們無需手工測試這個函數。這個函數很容易就修復了,因為未通過的測試讓我們得知新代碼破壞了函數原來的行為。
11.1.5 添加新測試
確定get_formatted_name() 又能正確地處理簡單的姓名後,我們再編寫一個測試,用於測試包含中間名的姓名。為此,我們在NamesTestCase 類中再添加一個方法:
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""測試name_function.py
"""
def test_first_last_name(self):
"""能夠正確地處理像Janis
Joplin這樣的姓名嗎?"""
formatted_name =
get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name,
'Janis Joplin')
def test_first_last_middle_name(self):
"""能夠正確地處理像Wolfgang
Amadeus Mozart這樣的姓名嗎?"""
❶ formatted_name = get_formatted_name(
'wolfgang', 'mozart', 'amadeus')
self.assertEqual(formatted_name,
'Wolfgang Amadeus Mozart')
unittest.main()
我們將這個方法命名為test_first_last_middle_name() 。方法名必須以test_打頭,這樣它才會在我們運行test_name_function.py時自動運行。這個方法名清楚地指出了它測試的是get_formatted_name() 的哪個行為,這樣,如果該測試未通過,我們就會馬上知道受影響的是哪種類型的姓名。在TestCase 類中使用很長的方法名是可以的;這些方法的名稱必須是描述性的,這才能讓你明白測試未通過時的輸出;這些方法由Python自動調用,你根本不用編寫調用它們的代碼。
為測試函數get_formatted_name() ,我們使用名、姓和中間名調用它(見❶),再使用assertEqual() 檢查返回的姓名是否與預期的姓名(名、中間名和姓)一致。我們再次運行test_name_function.py時,兩個測試都通過了:
..
----------------------------------------------------------------------
Ran 2
tests in 0.000s
OK
太好了!現在我們知道,這個函數又能正確地處理像Janis Joplin這樣的姓名了,我們還深信它也能夠正確地處理像Wolfgang Amadeus
Mozart這樣的姓名。
動手試一試
11-1 城市和國家 :編寫一個函數,它接受兩個形參:一個城市名和一個國家名。這個函數返回一個格式為City,
Country 的字串,如Santiago,
Chile 。將這個函數存儲在一個名為city_functions.py的模組中。
創建一個名為test_cities.py的程式,對剛編寫的函數進行測試(別忘了,你需要導入模組unittest 以及要測試的函數)。編寫一個名為test_city_country() 的方法,核實使用類似於'santiago' 和'chile' 這樣的值來調用前述函數時,得到的字串是正確的。運行test_cities.py ,確認測試test_city_country() 通過了。
11-2 人口數量 :修改前面的函數,使其包含第三個必不可少的形參population ,並返回一個格式為City, Country
- population xxx 的字串,如Santiago,
Chile - population 5000000 。運行test_cities.py,確認測試test_city_country() 未通過。
修改上述函數,將形參population 設置為可選的。再次運行test_cities.py,確認測試test_city_country() 又通過了。
再編寫一個名為test_city_country_population() 的測試,核實可以使用類似於'santiago' 、'chile' 和'population=5000000' 這樣的值來調用這個函數。再次運行test_cities.py,確認測試test_city_country_population() 通過了。
11.2 測試類
在本章前半部分,你編寫了針對單個函數的測試,下面來編寫針對類的測試。很多程式中都會用到類,因此能夠證明你的類能夠正確地工作會大有裨益。如果針對類的測試通過了,你就能確信對類所做的改進沒有意外地破壞其原有的行為。
11.2.1 各種斷言方法
Python在unittest.TestCase 類中提供了很多斷言方法。前面說過,斷言方法檢查你認為應該滿足的條件是否確實滿足。如果該條件確實滿足,你對程式列為的假設就得到了確認,你就可以確信其中沒有錯誤。如果你認為應該滿足的條件實際上並不滿足,Python將引發異常。
表11-1描述了6個常用的斷言方法。使用這些方法可核實返回的值等於或不等於預期的值、返回的值為True 或False 、返回的值在列表中或不在列表中。你只能在繼承unittest.TestCase 的類中使用這些方法,下面來看看如何在測試類時使用其中的一個。
表11-1 unittest Module中的斷言方法
|
方法 |
用途 |
|
assertEqual(a,
b) |
核實a == b |
|
assertNotEqual(a,
b) |
核實a != b |
|
assertTrue(x) |
核實x 為True |
|
assertFalse(x) |
核實x 為False |
|
assertIn(item , list ) |
核實 item 在 list 中 |
|
assertNotIn(item , list ) |
核實 item 不在 list 中 |
11.2.2 一個要測試的類
類的測試與函數的測試相似——你所做的大部分工作都是測試類中方法的行為,但存在一些不同之處,下面來編寫一個類進行測試。來看一個幫助管理匿名調查的類:
survey.py
class AnonymousSurvey():
"""收集匿名調查問卷的答案"""
❶ def __init__(self, question):
"""存儲一個問題,並為存儲答案做準備"""
self.question = question
self.responses = []
❷ def show_question(self):
"""顯示調查問卷"""
print(question)
❸ def store_response(self, new_response):
"""存儲單份調查答卷"""
self.responses.append(new_response)
❹ def show_results(self):
"""顯示收集到的所有答卷"""
print("Survey results:")
for response in responses:
print('- ' + response)
這個類首先存儲了一個你指定的調查問題(見❶),並創建了一個空清單,用於存儲答案。這個類包含列印調查問題的方法(見❷)、在答案列表中添加新答案的方法(見❸)以及將存儲在清單中的答案都列印出來的方法(見❹)。要創建這個類的實例,只需提供一個問題即可。有了表示調查的實例後,就可使用show_question() 來顯示其中的問題,可使用store_response() 來存儲答案,並使用show_results() 來顯示調查結果。
為證明AnonymousSurvey 類能夠正確地工作,我們來編寫一個使用它的程式:
language_survey.py
from
survey import AnonymousSurvey
#定義一個問題,並創建一個表示調查的AnonymousSurvey物件
question
= "What language did you first learn to speak?"
my_survey
= AnonymousSurvey(question)
#顯示問題並存儲答案
my_survey.show_question()
print("Enter
'q' at any time to quit.\n")
while
True:
response = input("Language: ")
if response == 'q':
break
my_survey.store_response(response)
# 顯示調查結果
print("\nThank
you to everyone who participated in the survey!")
my_survey.show_results()
這個程式定義了一個問題("What language did you
first learn to speak? " ),並使用這個問題創建了一個AnonymousSurvey 物件。接下來,這個程式調用show_question() 來顯示問題,並提示使用者輸入答案。收到每個答案的同時將其存儲起來。用戶輸入所有答案(輸入q 要求退出)後,調用show_results() 來列印調查結果:
What
language did you first learn to speak?
Enter
'q' at any time to quit.
Language:
English
Language:
Spanish
Language:
English
Language:
Mandarin
Language:
q
Thank
you to everyone who participated in the survey!
Survey
results:
-
English
-
Spanish
-
English
-
Mandarin
AnonymousSurvey 類可用於進行簡單的匿名調查。假設我們將它放在了模組survey 中,並想進行改進:讓每位用戶都可輸入多個答案;編寫一個方法,它只列出不同的答案,並指出每個答案出現了多少次;再編寫一個類,用於管理非匿名調查。
進行上述修改存在風險,可能會影響AnonymousSurvey 類的當前行為。例如,允許每位用戶輸入多個答案時,可能不小心修改了處理單個答案的方式。要確認在開發這個模組時沒有破壞既有行為,可以編寫針對這個類的測試。
11.2.3 測試AnonymousSurvey 類
下面來編寫一個測試,對AnonymousSurvey 類的行為的一個方面進行驗證:如果用戶面對調查問題時只提供了一個答案,這個答案也能被妥善地存儲。為此,我們將在這個答案被存儲後,使用方法assertIn() 來核實它包含在答案列表中:
test_survey.py
import unittest
from survey import AnonymousSurvey
❶ class TestAnonmyousSurvey(unittest.TestCase):
"""針對AnonymousSurvey類的測試"""
❷ def test_store_single_response(self):
"""測試單個答案會被妥善地存儲"""
question = "What language did
you first learn to speak?"
❸ my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
❹ self.assertIn('English',
my_survey.responses)
unittest.main()
我們首先導入了模組unittest 以及要測試的類AnonymousSurvey 。我們將測試用例命名為TestAnonymousSurvey ,它也繼承了unittest.TestCase (見❶)。第一個測試方法驗證調查問題的單個答案被存儲後,會包含在調查結果列表中。對於這個方法,一個不錯的描述性名稱是test_store_single_response() (見❷)。如果這個測試未通過,我們就能通過輸出中的方法名得知,在存儲單個調查答案方面存在問題。
要測試類的行為,需要創建其實例。在❸處,我們使用問題"What language did you first learn to speak?" 創建了一個名為my_survey 的實例,然後使用方法store_response() 存儲了單個答案English 。接下來,我們檢查English 是否包含在列表my_survey.responses 中,以核實這個答案是否被妥善地存儲了(見❹)。
當我們運行test_survey.py時,測試通過了:
.
----------------------------------------------------------------------
Ran 1
test in 0.001s
OK
這很好,但只能收集一個答案的調查用途不大。下面來核實用戶提供三個答案時,它們也將被妥善地存儲。為此,我們在TestAnonymousSurvey 中再添加一個方法:
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""針對AnonymousSurvey類的測試"""
def test_store_single_response(self):
"""測試單個答案會被妥善地存儲"""
--snip--
def
test_store_three_responses(self):
"""測試三個答案會被妥善地存儲"""
question = "What language did
you first learn to speak?"
my_survey = AnonymousSurvey(question)
❶ responses = ['English', 'Spanish',
'Mandarin']
for response in responses:
my_survey.store_response(response)
❷ for response in responses:
self.assertIn(response,
my_survey.responses)
unittest.main()
我們將這個方法命名為test_store_three_responses() ,並像test_store_single_response() 一樣,在其中創建一個調查物件。我們定義了一個包含三個不同答案的列表(見❶),再對其中每個答案都調用store_response() 。存儲這些答案後,我們使用一個迴圈來確認每個答案都包含在my_survey.responses 中(見❷)。
我們再次運行test_survey.py時,兩個測試(針對單個答案的測試和針對三個答案的測試)都通過了:
..
----------------------------------------------------------------------
Ran 2
tests in 0.000s
OK
前述做法的效果很好,但這些測試有些重複的地方。下面使用unittest 的另一項功能來提高它們的效率。
11.2.4 方法setUp()
在前面的test_survey.py中,我們在每個測試方法中都創建了一個AnonymousSurvey 實例,並在每個方法中都創建了答案。unittest.TestCase 類包含方法setUp() ,讓我們只需創建這些物件一次,並在每個測試方法中使用它們。如果你在TestCase 類中包含了方法setUp() ,Python將先運行它,再運行各個以test_打頭的方法。這樣,在你編寫的每個測試方法中都可使用在方法setUp() 中創建的物件了。
下面使用setUp() 來創建一個調查物件和一組答案,供方法test_store_single_response() 和test_store_three_responses() 使用:
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""針對AnonymousSurvey類的測試"""
def setUp(self):
"""
創建一個調查物件和一組答案,供使用的測試方法使用
"""
question = "What language did
you first learn to speak?"
❶ self.my_survey =
AnonymousSurvey(question)
❷ self.responses = ['English',
'Spanish', 'Mandarin']
def test_store_single_response(self):
"""測試單個答案會被妥善地存儲"""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.responses[0],
self.my_survey.responses)
def test_store_three_responses(self):
"""測試三個答案會被妥善地存儲"""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response,
self.my_survey.responses)
unittest.main()
方法setUp() 做了兩件事情:創建一個調查物件(見❶);創建一個答案列表(見❷)。存儲這兩樣東西的變數名包含首碼self (即存儲在屬性中),因此可在這個類的任何地方使用。這讓兩個測試方法都更簡單,因為它們都不用創建調查物件和答案。方法test_store_three_response() 核實self.responses 中的第一個答案——self.responses[0] ——被妥善地存儲,而方法test_store_three_response() 核實self.responses 中的全部三個答案都被妥善地存儲。
再次運行test_survey.py時,這兩個測試也都通過了。如果要擴展AnonymousSurvey ,使其允許每位用戶輸入多個答案,這些測試將很有用。修改代碼以接受多個答案後,可運行這些測試,確認存儲單個答案或一系列答案的行為未受影響。
測試自己編寫的類時,方法setUp() 讓測試方法編寫起來更容易:可在setUp() 方法中創建一系列實例並設置它們的屬性,再在測試方法中直接使用這些實例。相比於在每個測試方法中都創建實例並設置其屬性,這要容易得多。
注意 運行測試用例時,每完成一個單元測試,Python都列印一個字元:測試通過時列印一個句點;測試引發錯誤時列印一個E ;測試導致斷言失敗時列印一個F 。這就是你運行測試用例時,在輸出的第一行中看到的句點和字元數量各不相同的原因。如果測試用例包含很多單元測試,需要運行很長時間,就可通過觀察這些結果來獲悉有多少個測試通過了。
動手試一試
11-3 雇員 :編寫一個名為Employee 的類,其方法__init__() 接受名、姓和年薪,並將它們都存儲在屬性中。編寫一個名為give_raise() 的方法,它默認將年薪增加5000美元,但也能夠接受其他的年薪增加量。
為Employee 編寫一個測試用例,其中包含兩個測試方法:test_give_default_raise() 和test_give_custom_raise() 。使用方法setUp() ,以免在每個測試方法中都創建新的雇員實例。運行這個測試用例,確認兩個測試都通過了。
11.3 小結
在本章中,你學習了:如何使用模組unittest 中的工具來為函數和類編寫測試;如何編寫繼承unittest.TestCase 的類,以及如何編寫測試方法,以核實函數和類的行為符合預期;如何使用方法setUp() 來根據類高效地創建實例並設置其屬性,以便在類的所有測試方法中都可使用它們。
測試是很多初學者都不熟悉的主題。作為初學者,並非必須為你嘗試的所有項目編寫測試;但參與工作量較大的項目時,你應對自己編寫的函數和類的重要行為進行測試。這樣你就能夠更加確定自己所做的工作不會破壞專案的其他部分,你就能夠隨心所欲地改進既有代碼了。如果不小心破壞了原來的功能,你馬上就會知道,從而能夠輕鬆地修復問題。相比于等到不滿意的用戶報告bug後再採取措施,在測試未通過時採取措施要容易得多。
如果你在項目中包含了初步測試,其他程式師將更敬佩你,他們將能夠更得心應手地嘗試使用你編寫的代碼,也更願意與你合作開發項目。如果你要跟其他程式師開發的專案共用代碼,就必須證明你編寫的代碼通過了既有測試,通常還需要為你添加的新行為編寫測試。
請通過多開展測試來熟悉代碼測試過程。對於自己編寫的函數和類,請編寫針對其重要行為的測試,但在項目早期,不要試圖去編寫全覆蓋的測試用例,除非有充分的理由這樣做。
大澳飛宇註:
本書入門精華已為您連載完畢,謝謝閱讀。

0 留言:
發佈留言