《python程式設計從入門到實踐》讀書實踐筆記(二)
本文是《python程式設計從入門到實踐》讀書實踐筆記11章的內容,主要包含測試,為體現測試的重要性,獨立成文。
11 測試程式碼
寫在前面的話,以下是我這些年開發中和測試相關的血淚史。
- 對於一個bug,發現得越晚,處理它的成本就越高。
- bug在一個複雜系統中時,找到它要比處理它麻煩的多。
- 大多數bug都低階得令人髮指。
- 永遠無法找到所有bug,成本和安全需要互相妥協,極端一般都不那麼美好。
- 測試人員有他們的KPI,自己找的bug才適合自己
11.1函式自測、測試用例和unittest
Python標準庫unittest提供了程式碼測試工具,可以用於程式碼的單元測試。
如果要用unnitest,需要建一個unittest的類
比如,當前有一個函式,該函式被存在city_function.py中
def city_country(city, country, polulation=None): """根據輸入的城市,國家,人口,返回特定格式字串""" if polulation == None: city_country_rst = f"{city.title()}, {country.title()}" elif polulation is not None: city_country_rst = f"{city.title()}, {country.title()} - polulation {polulation}" return city_country_rst
再新建一個test_cities.py的檔案,以進行對剛才函式的測試
import unittest from city_function import * class CityFuncTestCase(unittest.TestCase): """測試city_function.py""" def test_city_country_only_func(self): """能夠正確地得到結果""" city_country_rst = city_country('shanghai', 'china') self.assertEqual(city_country_rst, 'Shanghai, China') def test_city_country_polulation_func(self): """能夠正確地得到結果""" city_country_rst = city_country('shanghai', 'china', 16_0000_0000) self.assertEqual(city_country_rst, 'Shanghai, China - polulation 1600000000') if __name__ == '__main__': unittest.main()
對於CityfuncTestCase類,其中的子函式(每一個測試用例)必須以test_開頭,這樣才能在執行unitest.main()時自動呼叫這些測試用例。
如果一個函式的外部互動較少,可以在測試時適當減少用例。比如在這個city_country函式中,就沒有增加polulation數值範圍的校驗。
11.2 類自測
類測試和函式測試幾乎一樣,都是在unittest中新建一個類,來測試需要的方法或屬性
11.2.4 方法setUp()
可以通過在測試類(比如剛才的CityFuncTestCase)中,增加setUp()方法,來在每一個測試用例呼叫前,增加一些相同的操作。對應的tearDown()方法中的內容會在每一個測試用例呼叫後執行。
被測試的類,儲存在classEmployee.py中
class Employee():
"""記錄僱員的資訊"""
def __init__(self, name, salary=2000):
self.name = name
self.salary = salary
def give_raise(self, amount=500):
self.salary += amount
測試指令碼test_classEmployee.py:
import unittest
from classEmployee import *
class testClassEmployee(unittest.TestCase):
"""針對Employee類的測試"""
def setUp(self):
"""建立一個員工,用於測試"""
self.default_emp = Employee('Zhangsan')
self.sp_emp = Employee('Lisi', salary=5000)
def test_default_new_employee(self):
"""測試預設薪水下的普通員工"""
self.assertEqual(self.default_emp.salary, 2000)
def test_sp_new_employee_with_salary_5000(self):
"""測試特定薪水下的新建員工"""
self.assertEqual(self.sp_emp.salary, 5000)
def test_employee_give_raise_default(self):
"""測試預設薪水下的普通員工"""
self.default_emp.give_raise()
self.assertEqual(self.default_emp.salary, 2500)
def test_employee_give_raise_2000(self):
"""測試預設薪水下的普通員工"""
self.default_emp.give_raise(amount=2000)
self.assertEqual(self.default_emp.salary, 4000)
if __name__ == '__main__':
unittest.main()
通過test_employee_give_raise_default()和test_employee_give_raise_2000()可以發現,單元測試的函式間是不會互相影響的。(這兩個函式都對self.default_emp進行了操作,但是這些操作並不互通)
unittest的其他資訊
最全面的肯定是python關於unittest的官方文件
其他一些blog也可以看起來,當然最主要的還是:
- 自測的願望
- 在實踐中不斷使用
後話
unittest只是python標準庫中的自測框架,其實還有一些框架可以選用。