Python單元測(cè)試入門(mén)到精通講解
一、入門(mén)單元測(cè)試
1.1 什么是單元測(cè)試?
單元測(cè)試是對(duì)代碼中的最小單元進(jìn)行測(cè)試,通常是函數(shù)或方法。其目標(biāo)是檢查這些單元是否按預(yù)期工作。單元測(cè)試通常涵蓋函數(shù)的各種輸入和邊界條件,以確保代碼的正確性。
1.2 Python的unittest模塊
Python的標(biāo)準(zhǔn)庫(kù)提供了unittest
模塊,用于編寫(xiě)和運(yùn)行單元測(cè)試。這是一個(gè)功能強(qiáng)大的工具,可以幫助你組織測(cè)試用例、運(yùn)行測(cè)試套件和生成測(cè)試報(bào)告。
1.3 編寫(xiě)第一個(gè)單元測(cè)試
從一個(gè)簡(jiǎn)單的示例開(kāi)始,編寫(xiě)一個(gè)函數(shù)并為其編寫(xiě)單元測(cè)試。
# mymath.py def add(a, b): return a + b
# test_mymath.py import unittest from mymath import add class TestAddition(unittest.TestCase): def test_add_integers(self): result = add(2, 3) self.assertEqual(result, 5) if __name__ == '__main__': unittest.main()
在上面的示例中,編寫(xiě)了一個(gè)簡(jiǎn)單的add
函數(shù),然后編寫(xiě)了一個(gè)單元測(cè)試類TestAddition
,并在其中定義了一個(gè)測(cè)試方法test_add_integers
,該方法使用self.assertEqual()
來(lái)驗(yàn)證add
函數(shù)的行為是否正確。
二、單元測(cè)試的基本概念
2.1 測(cè)試用例
測(cè)試用例是單元測(cè)試的基本單元,它包含一個(gè)或多個(gè)測(cè)試方法,用于測(cè)試代碼的不同方面。通常,每個(gè)測(cè)試方法對(duì)應(yīng)一個(gè)功能或函數(shù)。
2.2 斷言
斷言是單元測(cè)試中用于驗(yàn)證代碼行為的關(guān)鍵部分。它們是一種強(qiáng)有力的工具,用于檢查代碼是否按預(yù)期工作。Python的unittest模塊提供了多種斷言方法,以幫助你驗(yàn)證期望值和實(shí)際值之間的關(guān)系。
下面是一些常用的unittest斷言方法:
assertEqual(first, second, msg=None)
用于驗(yàn)證兩個(gè)值是否相等。如果first
和second
相等,斷言通過(guò),否則失敗。
self.assertEqual(result, expected)
assertNotEqual(first, second, msg=None)
用于驗(yàn)證兩個(gè)值是否不相等。如果first
和second
不相等,斷言通過(guò),否則失敗。
self.assertNotEqual(result, expected)
assertTrue(expr, msg=None)
用于驗(yàn)證表達(dá)式expr
的值是否為T(mén)rue。如果expr
為T(mén)rue,斷言通過(guò),否則失敗。
self.assertTrue(result)
assertFalse(expr, msg=None)
用于驗(yàn)證表達(dá)式expr
的值是否為False。如果expr
為False,斷言通過(guò),否則失敗。
self.assertFalse(result)
assertIn(member, container, msg=None)
用于驗(yàn)證member
是否在container
中。如果member
在container
中,斷言通過(guò),否則失敗。
self.assertIn(item, container)
assertNotIn(member, container, msg=None)
用于驗(yàn)證member
是否不在container
中。如果member
不在container
中,斷言通過(guò),否則失敗。
self.assertNotIn(item, container)
assertIsNone(expr, msg=None)
用于驗(yàn)證表達(dá)式expr
的值是否為None。如果expr
為None,斷言通過(guò),否則失敗。
self.assertIsNone(result)
assertIsNotNone(expr, msg=None)
用于驗(yàn)證表達(dá)式expr
的值是否不為None。如果expr
不為None,斷言通過(guò),否則失敗。
self.assertIsNotNone(result)
assertRaises(exc, callable, *args, **kwds)
用于驗(yàn)證調(diào)用callable
時(shí)是否引發(fā)了異常exc
。如果callable
引發(fā)了exc
異常,斷言通過(guò),否則失敗。
self.assertRaises(ValueError, some_function, arg1, arg2)
這些斷言方法使得編寫(xiě)單元測(cè)試更容易,因?yàn)樗鼈兲峁┝素S富的比較和驗(yàn)證選項(xiàng),幫助檢查代碼的正確性。根據(jù)測(cè)試需求,選擇適當(dāng)?shù)臄嘌苑椒?,?lái)編寫(xiě)全面的測(cè)試用例。
2.3 測(cè)試套件
測(cè)試套件(Test Suite)是一組測(cè)試用例的集合,用于一次性運(yùn)行多個(gè)測(cè)試。在Python的unittest框架中,可以使用unittest.TestLoader
來(lái)自動(dòng)發(fā)現(xiàn)和加載測(cè)試用例,并將它們組織成一個(gè)測(cè)試套件。
創(chuàng)建和運(yùn)行測(cè)試套件的基本步驟:
- 導(dǎo)入必要的模塊和類:
import unittest
- 創(chuàng)建一個(gè)測(cè)試用例類,該類繼承自
unittest.TestCase
。在這個(gè)類中,可以定義多個(gè)測(cè)試方法,每個(gè)方法用于測(cè)試不同的代碼單元。
class MyTestCase(unittest.TestCase): def test_method1(self): # 測(cè)試代碼1 def test_method2(self): # 測(cè)試代碼2
- 創(chuàng)建一個(gè)測(cè)試套件對(duì)象,使用
unittest.TestLoader
的loadTestsFromTestCase()
方法自動(dòng)加載測(cè)試用例:
loader = unittest.TestLoader() suite = loader.loadTestsFromTestCase(MyTestCase)
- 運(yùn)行測(cè)試套件,可以使用
unittest.TextTestRunner
來(lái)運(yùn)行測(cè)試并輸出結(jié)果:
runner = unittest.TextTestRunner() runner.run(suite)
這樣,可以一次性運(yùn)行多個(gè)測(cè)試方法,查看測(cè)試結(jié)果,以確保代碼的正確性。測(cè)試套件的使用有助于組織和管理大量的測(cè)試用例,使測(cè)試過(guò)程更加高效和可維護(hù)。
以下是一個(gè)完整的示例:
import unittest class MathTestCase(unittest.TestCase): def test_addition(self): self.assertEqual(1 + 1, 2) def test_subtraction(self): self.assertEqual(3 - 1, 2) if __name__ == '__main': loader = unittest.TestLoader() suite = loader.loadTestsFromTestCase(MathTestCase) runner = unittest.TextTestRunner() runner.run(suite)
運(yùn)行上述代碼將執(zhí)行MathTestCase
類中的兩個(gè)測(cè)試方法,并輸出測(cè)試結(jié)果。測(cè)試套件的使用可以更好地組織和運(yùn)行測(cè)試,以確保代碼的正確性。
2.4 setUp() 和 tearDown()
setUp()
和 tearDown()
是在每個(gè)測(cè)試方法之前和之后執(zhí)行的特殊方法,用于準(zhǔn)備測(cè)試環(huán)境和清理測(cè)試資源。這些方法是在 unittest
框架中的測(cè)試用例類中定義的,以確保每個(gè)測(cè)試方法都在相同的起始和結(jié)束狀態(tài)下運(yùn)行。
setUp()
setUp()
方法在每個(gè)測(cè)試方法之前執(zhí)行,通常用于準(zhǔn)備測(cè)試所需的資源、數(shù)據(jù)或設(shè)置。這可以包括創(chuàng)建對(duì)象、打開(kāi)文件、建立數(shù)據(jù)庫(kù)連接等。通過(guò)在 setUp()
中完成這些準(zhǔn)備工作,可以確保每個(gè)測(cè)試方法都在相同的初始條件下運(yùn)行,從而提高測(cè)試的一致性。
import unittest class MyTestCase(unittest.TestCase): def setUp(self): # 在每個(gè)測(cè)試方法之前執(zhí)行的準(zhǔn)備工作 self.data = [1, 2, 3, 4, 5] def test_method1(self): # 測(cè)試方法1使用了setUp中準(zhǔn)備的self.data self.assertEqual(sum(self.data), 15) def test_method2(self): # 測(cè)試方法2也可以使用setUp中準(zhǔn)備的self.data self.assertIn(3, self.data) if __name__ == '__main__': unittest.main()
tearDown()
tearDown()
方法在每個(gè)測(cè)試方法執(zhí)行后執(zhí)行,用于清理測(cè)試過(guò)程中產(chǎn)生的資源或數(shù)據(jù)。包括關(guān)閉文件、斷開(kāi)數(shù)據(jù)庫(kù)連接等。通過(guò)在 tearDown()
中進(jìn)行清理工作,確保測(cè)試過(guò)程不會(huì)留下不必要的資源或垃圾。
import unittest class MyTestCase(unittest.TestCase): def setUp(self): # 在每個(gè)測(cè)試方法之前執(zhí)行的準(zhǔn)備工作 self.file = open("test.txt", "w") def tearDown(self): # 在每個(gè)測(cè)試方法執(zhí)行后執(zhí)行的清理工作 self.file.close() def test_file_operation(self): # 測(cè)試文件操作 self.file.write("Test data") self.assertEqual(self.file.read(), "Test data") if __name__ == '__main__': unittest.main()
使用 setUp()
和 tearDown()
方法可以確保測(cè)試方法之間的隔離性,同時(shí)也有助于提高測(cè)試代碼的可維護(hù)性和可重用性。在每個(gè)測(cè)試方法中,可以使用 setUp()
中準(zhǔn)備的資源,然后在 tearDown()
中清理這些資源,以確保測(cè)試過(guò)程的一致性。
三、高級(jí)單元測(cè)試技巧
3.1 參數(shù)化測(cè)試
有時(shí)需要針對(duì)不同的輸入?yún)?shù)運(yùn)行相同的測(cè)試方法。unittest
支持參數(shù)化測(cè)試,使用@unittest.parameterized.parameterized
裝飾器來(lái)實(shí)現(xiàn)。
import unittest from mymath import add class TestAddition(unittest.TestCase): @unittest.parameterized.parameterized([ (2, 3, 5), (0, 0, 0), (-1, 1, 0) ]) def test_add_integers(self, a, b, expected): result = add(a, b) self.assertEqual(result, expected)
3.2 跳過(guò)和期望異常
在單元測(cè)試中,有時(shí)可能需要跳過(guò)某些測(cè)試方法或者期望測(cè)試方法引發(fā)異常。Python的unittest框架使用@unittest.skip()
和@unittest.expectedFailure
來(lái)實(shí)現(xiàn)這些需求。
跳過(guò)測(cè)試方法
有時(shí),希望跳過(guò)某個(gè)測(cè)試方法,以便在未來(lái)修復(fù)它之前不運(yùn)行它??梢允褂?code>@unittest.skip(reason)裝飾器來(lái)標(biāo)記一個(gè)測(cè)試方法,告訴unittest跳過(guò)這個(gè)方法。reason
參數(shù)是可選的,用于說(shuō)明為什么跳過(guò)這個(gè)測(cè)試方法。
import unittest class MyTestCase(unittest.TestCase): @unittest.skip("這個(gè)測(cè)試方法暫時(shí)跳過(guò)") def test_method1(self): # 測(cè)試代碼 def test_method2(self): # 測(cè)試代碼
在上面的示例中,test_method1
被標(biāo)記為跳過(guò),因此它不會(huì)在運(yùn)行時(shí)執(zhí)行。而test_method2
將繼續(xù)運(yùn)行。
期望異常
有時(shí),希望測(cè)試方法引發(fā)異常,以確保它們能夠正確處理異常情況??梢允褂?code>@unittest.expectedFailure裝飾器來(lái)標(biāo)記一個(gè)測(cè)試方法,告訴unittest期望它會(huì)失敗,即引發(fā)異常。
import unittest class MyTestCase(unittest.TestCase): @unittest.expectedFailure def test_method1(self): # 這個(gè)測(cè)試方法期望引發(fā)異常 with self.assertRaises(SomeException): # 測(cè)試代碼 def test_method2(self): # 正常的測(cè)試方法
在上面的示例中,test_method1
被標(biāo)記為期望失敗,因此即使它引發(fā)了異常,unittest也不會(huì)將其標(biāo)記為失敗。而test_method2
將繼續(xù)運(yùn)行。
這些功能有助于在測(cè)試代碼時(shí)更靈活地處理特定情況,以及在修復(fù)問(wèn)題之前跳過(guò)某些測(cè)試方法。
3.3 Mock和Stub
Mock和Stub是單元測(cè)試中常用的模擬對(duì)象或函數(shù),用于模擬外部依賴的行為。Python提供了一些庫(kù),如unittest.mock
,用于創(chuàng)建模擬對(duì)象。
from unittest.mock import Mock def test_function(): # 創(chuàng)建一個(gè)模擬對(duì)象 mock_obj = Mock() # 模擬對(duì)象的行為 mock_obj.some_method.return_value = 42 result = mock_obj.some_method() assert result == 42
四、測(cè)試覆蓋率和持續(xù)集成
4.1 測(cè)試覆蓋率
測(cè)試覆蓋率是一種度量標(biāo)準(zhǔn),用于衡量測(cè)試是否覆蓋了代碼中的各個(gè)部分。幫助了解哪些代碼已經(jīng)被測(cè)試,哪些代碼還沒(méi)有被測(cè)試,從而有助于提高代碼的質(zhì)量和可靠性。Python社區(qū)提供了許多工具來(lái)測(cè)量測(cè)試覆蓋率,其中最常用的是coverage.py
。
什么是coverage.py?
coverage.py
是Python的一種測(cè)試覆蓋率工具,幫助分析代碼中哪些部分被測(cè)試覆蓋,哪些部分未被測(cè)試覆蓋。通過(guò)收集有關(guān)代碼執(zhí)行的信息,coverage.py
生成覆蓋率報(bào)告,了解測(cè)試覆蓋的程度。
如何使用coverage.py?
要使用coverage.py
來(lái)測(cè)量測(cè)試覆蓋率,首先需要安裝:
pip install coverage
接下來(lái),使用coverage run
命令來(lái)運(yùn)行你的測(cè)試套件,同時(shí)收集代碼覆蓋率信息。例如:
coverage run -m unittest discover
這將運(yùn)行單元測(cè)試,并收集覆蓋率數(shù)據(jù)。
要生成覆蓋率報(bào)告,可以使用coverage report
命令:
coverage report
報(bào)告將顯示哪些代碼行被測(cè)試覆蓋,哪些未被覆蓋,以及測(cè)試覆蓋率的百分比。
另外,還可以使用coverage html
命令生成HTML格式的覆蓋率報(bào)告,以便更詳細(xì)地查看覆蓋情況:
coverage html
這將生成一個(gè)htmlcov
文件夾,其中包含HTML格式的報(bào)告文件,可以在瀏覽器中查看。
為什么測(cè)試覆蓋率重要?
測(cè)試覆蓋率是評(píng)估測(cè)試質(zhì)量的一個(gè)指標(biāo)。較高的測(cè)試覆蓋率通常表示你的測(cè)試用例覆蓋了更多的代碼路徑,從而降低了潛在的bug和問(wèn)題。然而,測(cè)試覆蓋率并不是唯一衡量測(cè)試質(zhì)量的標(biāo)準(zhǔn),因此它應(yīng)該與其他測(cè)試方法一起使用,以確保代碼的正確性、可維護(hù)性和可擴(kuò)展性。
總之,coverage.py
是一個(gè)有用的工具,可以幫助你測(cè)量測(cè)試覆蓋率,了解哪些代碼已經(jīng)被測(cè)試,哪些代碼還需要更多的測(cè)試用例。它有助于提高代碼質(zhì)量,并減少潛在的問(wèn)題。
4.2 持續(xù)集成
持續(xù)集成(Continuous Integration,CI)是一種開(kāi)發(fā)實(shí)踐,旨在通過(guò)自動(dòng)化構(gòu)建、測(cè)試和部署,確保每次代碼提交都是可運(yùn)行的,從而提高軟件開(kāi)發(fā)的效率和質(zhì)量。持續(xù)集成工具可以自動(dòng)構(gòu)建、測(cè)試和部署你的應(yīng)用程序,以確保代碼變更不會(huì)引入新的問(wèn)題。
以下是一些常見(jiàn)的持續(xù)集成工具,它們可以集成單元測(cè)試并在每次代碼變更時(shí)運(yùn)行測(cè)試套件:
Jenkins是一個(gè)流行的開(kāi)源持續(xù)集成工具,它支持各種編程語(yǔ)言和測(cè)試框架。你可以配置Jenkins以在代碼提交后自動(dòng)觸發(fā)構(gòu)建和測(cè)試過(guò)程,從而快速發(fā)現(xiàn)問(wèn)題。
Travis CI是一個(gè)云托管的持續(xù)集成服務(wù),專門(mén)用于GitHub倉(cāng)庫(kù)。它可以輕松集成單元測(cè)試,并在每次代碼推送到GitHub時(shí)自動(dòng)運(yùn)行測(cè)試套件。
CircleCI是另一個(gè)流行的持續(xù)集成工具,它支持各種編程語(yǔ)言和框架。你可以配置CircleCI以自動(dòng)運(yùn)行測(cè)試,并將測(cè)試結(jié)果報(bào)告集成到你的開(kāi)發(fā)工作流中。
GitHub Actions是GitHub自家提供的一項(xiàng)集成服務(wù),它允許你在GitHub倉(cāng)庫(kù)中配置工作流,包括構(gòu)建和測(cè)試。你可以創(chuàng)建自定義的GitHub Actions工作流來(lái)運(yùn)行單元測(cè)試并確保代碼的質(zhì)量。
GitLab CI/CD是GitLab集成的持續(xù)集成和持續(xù)交付工具。它允許你在GitLab倉(cāng)庫(kù)中配置CI/CD管道,包括自動(dòng)構(gòu)建和測(cè)試。
通過(guò)使用這些持續(xù)集成工具,可以確保每次代碼變更都經(jīng)過(guò)測(cè)試,從而盡早地發(fā)現(xiàn)和解決問(wèn)題。這有助于提高軟件質(zhì)量、加快開(kāi)發(fā)速度,并提供可靠的軟件產(chǎn)品。集成單元測(cè)試到持續(xù)集成流程是軟件開(kāi)發(fā)中的一項(xiàng)關(guān)鍵實(shí)踐,有助于減少潛在的問(wèn)題和錯(cuò)誤。
五、最佳實(shí)踐
5.1 命名規(guī)范
良好的命名規(guī)范對(duì)于單元測(cè)試非常重要。測(cè)試用例和測(cè)試方法的命名應(yīng)清晰明了,以便其他開(kāi)發(fā)人員理解測(cè)試的目的。
5.2 頻繁運(yùn)行測(cè)試
應(yīng)該經(jīng)常運(yùn)行單元測(cè)試,以確保代碼的及時(shí)檢查和修復(fù)。最好能夠?qū)y(cè)試自動(dòng)化,并在每次代碼提交時(shí)運(yùn)行測(cè)試套件。
5.3 編寫(xiě)?yīng)毩⒌臏y(cè)試
測(cè)試用例應(yīng)該相互獨(dú)立,不應(yīng)該依賴于其他測(cè)試的結(jié)果。這有助于快速識(shí)別和定位問(wèn)題。
總結(jié)
單元測(cè)試是Python編程中的關(guān)鍵實(shí)踐,有助于確保代碼的正確性和可維護(hù)性。通過(guò)合理的單元測(cè)試,可以在開(kāi)發(fā)過(guò)程中快速發(fā)現(xiàn)和解決問(wèn)題,提高代碼質(zhì)量,減少潛在的錯(cuò)誤。單元測(cè)試是每個(gè)Python開(kāi)發(fā)者都應(yīng)該掌握的技能,有助于構(gòu)建可靠的軟件應(yīng)用。
以上就是Python單元測(cè)試入門(mén)到精通講解的詳細(xì)內(nèi)容,更多關(guān)于Python單元測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python接口自動(dòng)化測(cè)試框架運(yùn)行原理及流程
這篇文章主要介紹了Python接口自動(dòng)化測(cè)試框架運(yùn)行原理及流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Python使用sys.exc_info()方法獲取異常信息
這篇文章主要介紹了Python使用sys.exc_info()方法獲取異常信息,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07Python實(shí)現(xiàn)九宮格式的朋友圈功能內(nèi)附“馬云”朋友圈
PIL(Python Imaging Library)是一個(gè)非常強(qiáng)大的Python庫(kù),但是它支持Python2.X, 在Python3中則使用的是Pillow庫(kù),它是從PIL中fork出來(lái)的一個(gè)分支。這篇文章主要介紹了用Python搞定九宮格式的朋友圈功能內(nèi)附“馬云”朋友圈 ,需要的朋友可以參考下2019-05-05Tensorflow讀取并輸出已保存模型的權(quán)重?cái)?shù)值方式
今天小編就為大家分享一篇Tensorflow讀取并輸出已保存模型的權(quán)重?cái)?shù)值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看不看2020-01-01python實(shí)現(xiàn)的發(fā)郵件功能示例
這篇文章主要介紹了python實(shí)現(xiàn)的發(fā)郵件功能,結(jié)合實(shí)例形式分析了Python使用網(wǎng)易郵箱發(fā)送郵件的相關(guān)操作技巧,需要的朋友可以參考下2019-09-09