摘要:也就是說(shuō),你可以將上述代碼中的看做單元測(cè)試,而將看做測(cè)試用例。在測(cè)試類(lèi)中的每一個(gè)測(cè)試方法都必須以開(kāi)頭,否則將不會(huì)被認(rèn)定是一個(gè)單元測(cè)試。
《Python編程:從入門(mén)到實(shí)踐》筆記。1. 前言
本章主要學(xué)習(xí)如何使用Python標(biāo)準(zhǔn)庫(kù)中的unittest模塊對(duì)代碼進(jìn)行簡(jiǎn)單的測(cè)試。
作為初學(xué)者,并非必須為你嘗試的所有項(xiàng)目編寫(xiě)測(cè)試;但參與工作量較大的項(xiàng)目時(shí),你應(yīng)對(duì)自己編寫(xiě)的函數(shù)和類(lèi)的重要行為進(jìn)行測(cè)試。這樣你就能夠更加確定自己所做的工作不會(huì)破壞項(xiàng)目的其他部分,你就能夠隨心所欲地改進(jìn)即有代碼。如果不小心破壞了原來(lái)的功能,你馬上就會(huì)知道,從而能夠輕松地修復(fù)問(wèn)題。相比于等到Bug出現(xiàn)后再去改,在測(cè)試未通過(guò)時(shí)采取措施要容易得多。而且,如果你想要分享你的項(xiàng)目,有測(cè)試的代碼更容易讓人接受。
2. 測(cè)試函數(shù) 2.1 一個(gè)能通過(guò)的測(cè)試以下是一個(gè)將用戶(hù)輸入的姓與名拼接的函數(shù):
# name_function.py def get_formatted_name(first, last): """返回一個(gè)整潔的完整姓名""" full_name = first + " " + last return full_name.title() if __name__ == "__main__": print("Enter "q" at any time to quit.") while True: first = input(" Please 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(" Neatly formatted name: " + formatted_name + ".")
當(dāng)然你也可以將if語(yǔ)句下面的代碼多帶帶放在一個(gè)文件中,并在該文件開(kāi)頭帶入get_formatted_name()函數(shù)。
對(duì)if __name__ == "__main__"的補(bǔ)充:
在Python中,模塊就是對(duì)象,所有模塊都有一個(gè)內(nèi)置屬性__name__,當(dāng)該模塊被導(dǎo)入時(shí),該模塊的__name__屬性會(huì)被置為模塊名,當(dāng)直接運(yùn)行該模塊,或者說(shuō)直接運(yùn)行該文件時(shí),該屬性就會(huì)使用默認(rèn)值"__main__",可以用一句經(jīng)典的話(huà)總結(jié)這個(gè)用法:
Make a script both importable and executable.
if語(yǔ)句下面的代碼相當(dāng)于對(duì)上面的函數(shù)的測(cè)試,不過(guò)這樣的測(cè)試每次都需要我們自己輸入數(shù)據(jù),并自己根據(jù)結(jié)果判斷代碼是否工作正常,如果代碼稍微多一點(diǎn),稍微復(fù)雜一點(diǎn),這樣的測(cè)試方法將會(huì)很繁瑣,所以,我們使用unittest模塊了測(cè)試代碼。
# 代碼test_name_function.py: import unittest from name_function import get_formatted_name class NamesTestCase(unittest.TestCase): """測(cè)試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() # 結(jié)果: . # 這里有個(gè)實(shí)心句點(diǎn) ---------------------------------------------------------------------- Ran 1 test in 0.001s OK
這里先明確兩個(gè)概念:
單元測(cè)試:用于核實(shí)函數(shù)在某個(gè)方面沒(méi)有問(wèn)題
測(cè)試用例:一組單元測(cè)試,這些單元測(cè)試一起核實(shí)函數(shù)在各種情況下的行為都符合要求。
也就是說(shuō),你可以將上述代碼中的test_first_last_name看做單元測(cè)試,而將NamesTestCase看做測(cè)試用例。
一般測(cè)試文件多帶帶放在一個(gè)文件夾中,也可以將測(cè)試都放在一個(gè)文件中。
為函數(shù)編寫(xiě)測(cè)試用例,可先導(dǎo)入unittest模塊和要測(cè)試的函數(shù),再創(chuàng)建一個(gè)繼承unittest.TestCase的類(lèi),并編寫(xiě)一系列方法對(duì)函數(shù)行為的不同方面進(jìn)行測(cè)試。在測(cè)試用,我們使用斷言self.assertEqual()(并不是只有這一個(gè)斷言函數(shù))來(lái)判斷結(jié)果與期望是否相同。在測(cè)試類(lèi)中的每一個(gè)測(cè)試方法都必須以test_開(kāi)頭,否則將不會(huì)被認(rèn)定是一個(gè)單元測(cè)試。最后我們通過(guò)unittest.main()來(lái)運(yùn)行這個(gè)文件中的所有測(cè)試。當(dāng)測(cè)試通過(guò)時(shí),結(jié)果中會(huì)先輸出一個(gè)實(shí)心句點(diǎn),輸出幾個(gè)句點(diǎn)表示通過(guò)了幾個(gè)單元測(cè)試,然后輸出單元測(cè)試數(shù)目,最后輸出OK。
2.2 一個(gè)不能通過(guò)的測(cè)試外國(guó)人的名字還有中間名,以上代碼并未考慮這個(gè)情況。我們通過(guò)將上述代碼改成含有中間名的版本來(lái)演示測(cè)試不通過(guò)的情況:
# 代碼: def get_formatted_name(first, middle, last): """返回一個(gè)整潔的完整姓名""" full_name = first + " " + middle + " " + last return full_name.title() # 其余代碼均不變 # 運(yùn)行上面測(cè)試代碼后的結(jié)果: E ====================================================================== ERROR: test_first_last_name (__main__.NamesTestCase) 能夠正確地處理像Janis Joplin這樣的名字嗎? ---------------------------------------------------------------------- Traceback (most recent call last): File "test_name_function.py", line 10, 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.001s FAILED (errors=1)
第一行輸出了一個(gè)字母E,traceback指出缺少了參數(shù)。如果你檢查的條件沒(méi)錯(cuò),測(cè)試通過(guò)了意味著函數(shù)的行為是對(duì)的,而測(cè)試未通過(guò)意味著你編寫(xiě)的新代碼有錯(cuò)。因此,測(cè)試未通過(guò)時(shí),不是去修改測(cè)試代碼,而失去修改你編寫(xiě)的代碼。
2.3 添加新測(cè)試以下我們將上述的get_formatted_name()函數(shù)修改為能自動(dòng)處理中間名的函數(shù),并在測(cè)試文件中添加一個(gè)單元測(cè)試:
# name_function.py def get_formatted_name(first, last, middle=""): """返回一個(gè)整潔的完整姓名""" if middle: full_name = first + " " + middle + " " + last else: full_name = first + " " + last return full_name.title() # test_name_function.py import unittest from chapter11 import get_formatted_name class NamesTestCase(unittest.TestCase): """測(cè)試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() # 結(jié)果: .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK3. 測(cè)試類(lèi)
前面講的都是對(duì)函數(shù)的測(cè)試,這里我們開(kāi)始對(duì)類(lèi)的測(cè)試。在測(cè)試之前,先介紹幾種常用的斷言方法:
方法 | 用途 |
---|---|
assertEqual(a, b) | 核實(shí) a == b |
assertNotEqual(a, b) | 核實(shí) a != b |
assertTrue(x) | 核實(shí)x為T(mén)rue |
assertFalse(x) | 核實(shí)x為False |
assertIn(item, list) | 核實(shí)item在list中 |
assertNotIn(item, list) | 核實(shí)item不在list中 |
下面創(chuàng)建一個(gè)匿名調(diào)查類(lèi):
# survey.py class AnonymousSurvey: """收集匿名調(diào)查問(wèn)卷的答案""" def __init__(self, question): """存儲(chǔ)一個(gè)問(wèn)題,并為存儲(chǔ)答案做準(zhǔn)備""" self.question = question self.responses = [] def show_question(self): """顯示調(diào)查問(wèn)卷""" print(self.question) def store_response(self, new_response): """存儲(chǔ)單份調(diào)查問(wèn)卷""" self.responses.append(new_response) def show_results(self): """顯示收集到的所有答卷""" print("Survey results:") for response in self.responses: print("- " + response)
以下是對(duì)該類(lèi)的測(cè)試代碼:
# test_survey.py import unittest from chapter11 import AnonymousSurvey class TestAnonymousSurvey(unittest.TestCase): """針對(duì)AnonymousSurvey類(lèi)的測(cè)試""" def setUp(self): """創(chuàng)建一個(gè)調(diào)查對(duì)象和一組答案,共測(cè)試方法使用""" 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): """測(cè)試單個(gè)答案唄妥善地存儲(chǔ)""" self.my_survey.store_response(self.responses[0]) self.assertIn(self.responses[0], self.my_survey.responses) def test_store_three_responses(self): """測(cè)試三個(gè)答案會(huì)被妥善地存儲(chǔ)""" 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() # 結(jié)果: .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
這里的setUp()方法相當(dāng)于普通函數(shù)的__init__()方法,用于初始化這個(gè)測(cè)試類(lèi),減少重復(fù)代碼,比如,如果不用setUp()方法,那么question變量在每個(gè)測(cè)試函數(shù)中都要聲明一次,十分麻煩低效。你過(guò)測(cè)試類(lèi)中包含了setUp()方法,Python將先運(yùn)行它,再運(yùn)行各個(gè)以test_開(kāi)頭的方法。
至此,Python的基礎(chǔ)部分大致結(jié)束,后面將是項(xiàng)目部分,以后可能還會(huì)對(duì)基礎(chǔ)部分進(jìn)行補(bǔ)充。
迎大家關(guān)注我的微信公眾號(hào)"代碼港" & 個(gè)人網(wǎng)站 www.vpointer.net ~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41791.html
摘要:也就是說(shuō),你可以將上述代碼中的看做單元測(cè)試,而將看做測(cè)試用例。在測(cè)試類(lèi)中的每一個(gè)測(cè)試方法都必須以開(kāi)頭,否則將不會(huì)被認(rèn)定是一個(gè)單元測(cè)試。 《Python編程:從入門(mén)到實(shí)踐》筆記。本章主要學(xué)習(xí)如何使用Python標(biāo)準(zhǔn)庫(kù)中的unittest模塊對(duì)代碼進(jìn)行簡(jiǎn)單的測(cè)試。 1. 前言 作為初學(xué)者,并非必須為你嘗試的所有項(xiàng)目編寫(xiě)測(cè)試;但參與工作量較大的項(xiàng)目時(shí),你應(yīng)對(duì)自己編寫(xiě)的函數(shù)和類(lèi)的重要行為進(jìn)行測(cè)...
摘要:本章主要講述條件語(yǔ)句等結(jié)構(gòu)。是一條包羅萬(wàn)象的語(yǔ)句,只要不滿(mǎn)足前面的條件,其中的代碼就會(huì)執(zhí)行,這可能會(huì)引入無(wú)效甚至惡意的數(shù)據(jù)。使用語(yǔ)句處理列表語(yǔ)句常和循環(huán)結(jié)構(gòu)配合使用。 《Python編程:從入門(mén)到實(shí)踐》筆記。本章主要講述條件語(yǔ)句if, if-else, if-elif, if-elif-else等結(jié)構(gòu)。 1. 條件測(cè)試 包括了相等,不等,大于,小于,大于等于,小于等于,存在于,與或非等...
摘要:例如,以下對(duì)兩個(gè)的相應(yīng)元素求和這個(gè)例子很好的解釋了如何構(gòu)建中所謂的迭代器代數(shù)的函數(shù)的含義。為簡(jiǎn)單起見(jiàn),假設(shè)輸入的長(zhǎng)度可被整除。接受兩個(gè)參數(shù)一個(gè)可迭代的正整數(shù)最終會(huì)在中個(gè)元素的所有組合的元組上產(chǎn)生一個(gè)迭代器。 前言 大家好,今天想和大家分享一下我的itertools學(xué)習(xí)體驗(yàn)及心得,itertools是一個(gè)Python的自帶庫(kù),內(nèi)含多種非常實(shí)用的方法,我簡(jiǎn)單學(xué)習(xí)了一下,發(fā)現(xiàn)可以大大提升工作...
摘要:每個(gè)模塊都有對(duì)應(yīng)的分支內(nèi)容,并且分支內(nèi)容都分為參考資料練習(xí)題交流討論三個(gè)內(nèi)容,我最喜歡的是練習(xí)題,之前都是非正規(guī)軍的學(xué)習(xí),沒(méi)有系統(tǒng)訓(xùn)練過(guò),現(xiàn)在有技能樹(shù)測(cè)評(píng)終于可以把之前散亂的知識(shí)點(diǎn)總結(jié)在一起了。祝大家都能在技能樹(shù)測(cè)評(píng)判斷自己在哪個(gè)級(jí)別的。 通過(guò)《Python技能樹(shù)測(cè)評(píng)》判斷自己在哪個(gè)級(jí)別: ...
摘要:本章主要是學(xué)習(xí)的文件操作,主要是從文件中讀取數(shù)據(jù)以及將數(shù)據(jù)存儲(chǔ)到文件中,還有錯(cuò)誤處理,異常類(lèi),模塊等。函數(shù)返回一個(gè)文件對(duì)象,用于接收該對(duì)象。異常中使用被稱(chēng)為異常的特殊對(duì)象來(lái)管理程序執(zhí)行期間發(fā)生的錯(cuò)誤。 《Python編程:從入門(mén)到實(shí)踐》筆記。本章主要是學(xué)習(xí)Python的文件操作,主要是從文件中讀取數(shù)據(jù)以及將數(shù)據(jù)存儲(chǔ)到文件中,還有錯(cuò)誤處理,異常類(lèi),json模塊等。 1. 從文件中讀數(shù)據(jù) ...
閱讀 1412·2021-11-04 16:11
閱讀 3083·2021-10-12 10:11
閱讀 3014·2021-09-29 09:47
閱讀 1641·2021-09-22 15:40
閱讀 1046·2019-08-29 15:43
閱讀 2831·2019-08-29 13:50
閱讀 1610·2019-08-29 13:28
閱讀 2717·2019-08-29 12:54