python基礎教程(第三版)學習筆記(十六)
第十六章 測試基礎
除錯是程式設計師躲不開的宿命,是程式設計工作的有機組成部分。 本章介紹測試的基本知識。培養如何養成在程式設計中進行測試的習慣,並介紹一些可幫 助編寫測試的工具。
16.1 先測試再編碼
要避免程式碼在開發途中被淘汰,必須能夠應對變化並具備一定的靈活性,因此為程式的各個 部分編寫測試至關重要(這稱為單元測試),而且是應用程式設計工作的重要組成部分。極限編 程先鋒引入了“測試一點點,再編寫一點點程式碼”的理念。換而言之,測試在先,編碼在後。這也稱為測試驅動的程式設計。
16.1.1 準確的需求說明
開發軟體時,必須先知道軟體要解決什麼問題——要實現什麼樣的目標。要闡明程式的目標,可編寫需求說明,也就是描述程式必須滿足何種需求的文件(或便條)。 測試程式可以包含在程式內如:
#計算矩形面積
def rect_area(heigth,width): #程式中被呼叫的函式
return heigth*heigth #函式中有一處錯誤
height = 3
width = 4
correct_answer = 12 #設定執行結果
answer = rect_area(height, width)
if answer == correct_answer: #對執行結果進行判斷
print('程式測試通過 ')
else:
print('程式中存在錯誤!')
執行結果:
C:\Users\zhx\AppData\Local\Programs\Python\Python37\python.exe E:/pythonProjects/twisted/finger.py 程式中存在錯誤! Process finished with exit code 0
16.1.2 做好應對變化的準備
自動化測試不僅可在你編寫程式時提供極大的幫助,還有助於在你修改程式碼時避免累積錯 誤,這在程式規模很大時尤其重要。
16.1.3 測試四步曲
(1) 確定需要實現的新功能。可將其記錄下來,再為之編寫一個測試。
(2) 編寫實現功能的框架程式碼,讓程式能夠執行(不存在語法錯誤之類的問題),但測試依然 無法通過。測試失敗是很重要的,因為這樣你才能確定它可能失敗。 不斷重複這 個過程:確定測試失敗後,再試圖讓它成功。
(3) 編寫讓測試剛好能夠通過的程式碼。
(4) 改進(重構)程式碼以全面而準確地實現所需的功能,同時確保測試依然能夠成功。
16.2 測試工具
有兩個傑出的模組可替你自動完成測試過程。
一是unittest:一個通用的測試框架。
一是 doctest:一個更簡單的模組,是為檢查文件而設計的,但也非常適合用來編寫單元測試。
16.2.1 doctest
使用doctest非常方便,只要在模組最後新增如下程式碼即可:
#... ...以上是模組主體
if __name__=='__main__':
import doctest,模組名
doctest.testmod(模組名)
16.2.2 unittest
雖然doctest使用起來很容易,但unittest(基於流行的Java測試框架JUnit)更靈活、更強大。
unittest的使用和doctest類似:
import json
import unittest
from area import area
f = open('illinois.json', 'r')
illinois = json.loads(f.read())
world = {
'type': 'Polygon',
'coordinates': [
[
[-180, -90],
[-180, 90],
[180, 90],
[180, -90],
[-180, -90]
]
]
}
illinois_area = 145978332359.36746
world_area = 511207893395811.06
class AreaTestCase(unittest.TestCase):
def test_area_illinois_with_string(self):
""" illinois.json檔案輸入計算機 """
# 回到檔案的頂端
f.seek(0)
illinois = f.read()
self.assertEqual(round(area(illinois), 2), round(illinois_area, 2))
def test_area_illinois(self):
""" Compute the area of illinois """
self.assertEqual(round(area(illinois), 2), round(illinois_area, 2))
def test_area_world(self):
""" Compute the area of the whole world """
self.assertEqual(area(world), world_area)
def test_point_area(self):
""" Compute the area of a point """
self.assertEqual(area({'type': 'Point', 'coordinates': [0, 0]}), 0)
def test_liststring_area(self):
""" Compute the area of a line string """
self.assertEqual(area({'type': 'LineString', 'coordinates': [[0, 0], [1, 1]]}), 0)
def test_geometry_collection_area(self):
""" Compute the area of a geometry collection """
total = illinois_area + world_area
self.assertEqual(area({'type': 'GeometryCollection', 'geometries': [world, illinois]}), total)
if __name__ == '__main__':
unittest.main()
函式unittest.main負責替你執行測試:例項化所有的TestCase子類,並執行所有名稱以test 打頭的方法 。
執行結果:
C:\Users\xx\AppData\Local\Programs\Python\Python37\python.exe E:/pythonProjects/twisted/finger.py
......
----------------------------------------------------------------------
Ran 6 tests in 0.004s
OK
Process finished with exit code 0
其中......代表六個函式通過測試,如果不能通過測試會顯示F。
附 illinois.json檔案:
{
"type": "MultiPolygon",
"coordinates": [[
[
[
-88.071564,
37.51099
],
[
-88.087883,
37.476273
],
[
-88.311707,
37.442852
],
[
-88.359177,
37.409309
],
[
-88.419853,
37.420292
],
[
-88.467644,
37.400757
],
[
-88.511322,
37.296852
],
[
-88.501427,
37.257782
],
[
-88.450699,
37.205669
],
[
-88.422516,
37.15691
],
[
-88.45047,
37.098671
],
[
-88.476799,
37.072144
],
[
-88.4907,
37.06818
],
[
-88.517273,
37.06477
],
[
-88.559273,
37.072815
],
[
-88.61422,
37.109047
],
[
-88.68837,
37.13541
],
[
-88.739113,
37.141182
],
[
-88.746506,
37.152107
],
[
-88.863289,
37.202194
],
[
-88.932503,
37.218407
],
[
-88.993172,
37.220036
],
[
-89.065033,
37.18586
],
[
-89.116821,
37.112137
],
[
-89.146347,
37.093185
],
[
-89.169548,
37.064236
],
[
-89.174332,
37.025711
],
[
-89.150246,
36.99844
],
[
-89.12986,
36.988113
],
[
-89.193512,
36.986771
],
[
-89.210052,
37.028973
],
[
-89.237679,
37.041733
],
[
-89.264053,
37.087124
],
[
-89.284233,
37.091244
],
[
-89.303291,
37.085384
],
[
-89.3097,
37.060909
],
[
-89.264244,
37.027733
],
[
-89.262001,
37.008686
],
[
-89.282768,
36.999207
],
[
-89.310982,
37.009682
],
[
-89.38295,
37.049213
],
[
-89.37999,
37.099083
],
[
-89.423798,
37.137203
],
[
-89.440521,
37.165318
],
[
-89.468216,
37.224266
],
[
-89.465309,
37.253731
],
[
-89.489594,
37.256001
],
[
-89.513885,
37.276402
],
[
-89.513885,
37.304962
],
[
-89.50058,
37.329441
],
[
-89.468742,
37.339409
],
[
-89.435738,
37.355717
],
[
-89.427574,
37.411018
],
[
-89.453621,
37.453186
],
[
-89.494781,
37.491726
],
[
-89.524971,
37.571957
],
[
-89.513367,
37.615929
],
[
-89.51918,
37.650375
],
[
-89.513374,
37.67984
],
[
-89.521523,
37.694798
],
[
-89.581436,
37.706104
],
[
-89.666458,
37.745453
],
[
-89.675858,
37.78397
],
[
-89.691055,
37.804794
],
[
-89.728447,
37.840992
],
[
-89.851715,
37.905064
],
[
-89.861046,
37.905487
],
[
-89.866814,
37.891876
],
[
-89.900551,
37.875904
],
[
-89.937874,
37.878044
],
[
-89.978912,
37.911884
],
[
-89.958229,
37.963634
],
[
-90.010811,
37.969318
],
[
-90.041924,
37.993206
],
[
-90.119339,
38.032272
],
[
-90.134712,
38.053951
],
[
-90.207527,
38.088905
],
[
-90.254059,
38.122169
],
[
-90.289635,
38.166817
],
[
-90.336716,
38.188713
],
[
-90.364769,
38.234299
],
[
-90.369347,
38.323559
],
[
-90.358688,
38.36533
],
[
-90.339607,
38.390846
],
[
-90.301842,
38.427357
],
[
-90.265785,
38.518688
],
[
-90.26123,
38.532768
],
[
-90.240944,
38.562805
],
[
-90.183708,
38.610271
],
[
-90.183578,
38.658772
],
[
-90.20224,
38.700363
],
[
-90.196571,
38.723965
],
[
-90.163399,
38.773098
],
[
-90.135178,
38.785484
],
[
-90.121727,
38.80051
],
[
-90.113121,
38.830467
],
[
-90.132812,
38.853031
],
[
-90.243927,
38.914509
],
[
-90.278931,
38.924717
],
[
-90.31974,
38.924908
],
[
-90.413071,
38.96233
],
[
-90.469841,
38.959179
],
[
-90.530426,
38.891609
],
[
-90.570328,
38.871326
],
[
-90.627213,
38.880795
],
[
-90.668877,
38.935253
],
[
-90.70607,
39.037792
],
[
-90.707588,
39.058178
],
[
-90.690399,
39.0937
],
[
-90.716736,
39.144211
],
[
-90.718193,
39.195873
],
[
-90.732338,
39.224747
],
[
-90.738083,
39.24781
],
[
-90.779343,
39.296803
],
[
-90.850494,
39.350452
],
[
-90.947891,
39.400585
],
[
-91.036339,
39.444412
],
[
-91.064384,
39.473984
],
[
-91.093613,
39.528927
],
[
-91.156189,
39.552593
],
[
-91.203247,
39.600021
],
[
-91.317665,
39.685917
],
[
-91.367088,
39.72464
],
[
-91.373421,
39.761272
],
[
-91.381714,
39.803772
],
[
-91.449188,
39.863049
],
[
-91.450989,
39.885242
],
[
-91.434052,
39.901829
],
[
-91.430389,
39.921837
],
[
-91.447243,
39.946064
],
[
-91.487289,
40.005753
],
[
-91.504005,
40.066711
],
[
-91.516129,
40.134544
],
[
-91.506546,
40.200459
],
[
-91.498932,
40.251377
],
[
-91.486694,
40.309624
],
[
-91.448593,
40.371902
],
[
-91.418816,
40.386875
],
[
-91.385757,
40.392361
],
[
-91.372757,
40.402988
],
[
-91.385399,
40.44725
],
[
-91.374794,
40.503654
],
[
-91.382103,
40.528496
],
[
-91.412872,
40.547993
],
[
-91.411118,
40.572971
],
[
-91.37561,
40.603439
],
[
-91.262062,
40.639545
],
[
-91.214912,
40.643818
],
[
-91.162498,
40.656311
],
[
-91.129158,
40.682148
],
[
-91.119987,
40.705402
],
[
-91.092751,
40.761547
],
[
-91.088905,
40.833729
],
[
-91.04921,
40.879585
],
[
-90.983276,
40.923927
],
[
-90.960709,
40.950504
],
[
-90.954651,
41.070362
],
[
-90.957787,
41.104359
],
[
-90.990341,
41.144371
],
[
-91.018257,
41.165825
],
[
-91.05632,
41.176258
],
[
-91.101524,
41.231522
],
[
-91.102348,
41.267818
],
[
-91.07328,
41.334896
],
[
-91.055786,
41.401379
],
[
-91.027489,
41.423508
],
[
-91.000694,
41.431084
],
[
-90.949654,
41.421234
],
[
-90.844139,
41.444622
],
[
-90.7799,
41.449821
],
[
-90.708214,
41.450062
],
[
-90.658791,
41.462318
],
[
-90.6007,
41.509586
],
[
-90.54084,
41.52597
],
[
-90.454994,
41.527546
],
[
-90.434967,
41.543579
],
[
-90.423004,
41.567272
],
[
-90.348366,
41.586849
],
[
-90.339348,
41.602798
],
[
-90.341133,
41.64909
],
[
-90.326027,
41.722736
],
[
-90.304886,
41.756466
],
[
-90.25531,
41.781738
],
[
-90.195839,
41.806137
],
[
-90.154518,
41.930775
],
[
-90.14267,
41.983963
],
[
-90.150536,
42.033428
],
[
-90.168098,
42.061043
],
[
-90.166649,
42.103745
],
[
-90.176086,
42.120502
],
[
-90.191574,
42.122688
],
[
-90.230934,
42.159721
],
[
-90.323601,
42.197319
],
[
-90.367729,
42.210209
],
[
-90.407173,
42.242645
],
[
-90.417984,
42.263924
],
[
-90.427681,
42.340633
],
[
-90.441597,
42.360073
],
[
-90.491043,
42.388783
],
[
-90.563583,
42.421837
],
[
-90.605827,
42.46056
],
[
-90.648346,
42.475643
],
[
-90.651772,
42.494698
],
[
-90.638329,
42.509361
],
[
-90.419975,
42.508362
],
[
-89.923569,
42.504108
],
[
-89.834618,
42.50346
],
[
-89.400497,
42.49749
],
[
-89.359444,
42.497906
],
[
-88.939079,
42.490864
],
[
-88.764954,
42.490906
],
[
-88.70652,
42.489655
],
[
-88.297897,
42.49197
],
[
-88.194702,
42.489613
],
[
-87.79731,
42.489132
],
[
-87.836945,
42.314213
],
[
-87.760239,
42.156456
],
[
-87.670547,
42.059822
],
[
-87.612625,
41.847332
],
[
-87.529861,
41.723591
],
[
-87.532646,
41.469715
],
[
-87.532448,
41.301304
],
[
-87.531731,
41.173756
],
[
-87.532021,
41.00993
],
[
-87.532669,
40.745411
],
[
-87.53717,
40.49461
],
[
-87.535675,
40.483246
],
[
-87.535339,
40.166195
],
[
-87.535774,
39.887302
],
[
-87.535576,
39.609341
],
[
-87.538567,
39.477448
],
[
-87.540215,
39.350525
],
[
-87.597664,
39.338268
],
[
-87.625237,
39.307404
],
[
-87.610619,
39.297661
],
[
-87.615799,
39.281418
],
[
-87.606895,
39.258163
],
[
-87.584564,
39.248753
],
[
-87.588593,
39.208466
],
[
-87.594208,
39.198128
],
[
-87.607925,
39.196068
],
[
-87.644257,
39.168507
],
[
-87.670326,
39.146679
],
[
-87.659454,
39.130653
],
[
-87.662262,
39.113468
],
[
-87.631668,
39.103943
],
[
-87.630867,
39.088974
],
[
-87.612007,
39.084606
],
[
-87.58532,
39.062435
],
[
-87.581749,
38.995743
],
[
-87.591858,
38.994083
],
[
-87.547905,
38.977077
],
[
-87.53347,
38.963703
],
[
-87.530182,
38.931919
],
[
-87.5392,
38.904861
],
[
-87.559059,
38.869812
],
[
-87.550507,
38.857891
],
[
-87.507889,
38.795559
],
[
-87.519028,
38.776699
],
[
-87.508003,
38.769722
],
[
-87.508316,
38.736633
],
[
-87.543892,
38.685974
],
[
-87.588478,
38.672169
],
[
-87.625191,
38.642811
],
[
-87.628647,
38.622917
],
[
-87.619827,
38.599209
],
[
-87.640594,
38.593178
],
[
-87.652855,
38.573872
],
[
-87.672943,
38.547424
],
[
-87.65139,
38.515369
],
[
-87.653534,
38.500443
],
[
-87.679909,
38.504005
],
[
-87.692818,
38.481533
],
[
-87.756096,
38.466125
],
[
-87.758659,
38.457096
],
[
-87.738953,
38.44548
],
[
-87.748428,
38.417965
],
[
-87.784019,
38.378124
],
[
-87.834503,
38.352524
],
[
-87.850082,
38.286098
],
[
-87.863007,
38.285362
],
[
-87.874039,
38.316788
],
[
-87.883446,
38.315552
],
[
-87.888466,
38.300659
],
[
-87.914108,
38.281048
],
[
-87.913651,
38.302345
],
[
-87.925919,
38.304771
],
[
-87.980019,
38.241085
],
[
-87.986008,
38.234814
],
[
-87.977928,
38.200714
],
[
-87.932289,
38.171131
],
[
-87.931992,
38.157528
],
[
-87.950569,
38.136913
],
[
-87.973503,
38.13176
],
[
-88.018547,
38.103302
],
[
-88.012329,
38.092346
],
[
-87.964867,
38.096748
],
[
-87.975296,
38.073307
],
[
-88.034729,
38.054085
],
[
-88.043091,
38.04512
],
[
-88.041473,
38.038303
],
[
-88.021698,
38.033531
],
[
-88.029213,
38.008236
],
[
-88.021706,
37.975056
],
[
-88.042511,
37.956264
],
[
-88.041771,
37.934498
],
[
-88.064621,
37.929783
],
[
-88.078941,
37.944
],
[
-88.084,
37.92366
],
[
-88.030441,
37.917591
],
[
-88.026588,
37.905758
],
[
-88.044868,
37.896004
],
[
-88.100082,
37.90617
],
[
-88.101456,
37.895306
],
[
-88.075737,
37.867809
],
[
-88.034241,
37.843746
],
[
-88.042137,
37.827522
],
[
-88.089264,
37.831249
],
[
-88.086029,
37.817612
],
[
-88.035576,
37.805683
],
[
-88.072472,
37.735401
],
[
-88.133636,
37.700745
],
[
-88.15937,
37.660686
],
[
-88.157631,
37.628479
],
[
-88.134171,
37.583572
],
[
-88.071564,
37.51099
]
]
]]
}
16.3 超越單元測試
要探索程式,還有其他一些方式,下面將介紹兩個工具:原始碼檢查和效能分析。
16.3.1 使用 PyChecker 和 PyLint 檢查原始碼
長期以來,PyChecker(pychecker.sf.net)都是用於檢查Python原始碼的唯一工具,能夠找出 諸如給函式提供的引數不對等錯誤。(當然,標準庫中還有tabnanny,但沒那麼強大,只檢查縮 進是否正確。)之後出現了PyLint(pylint.org),它支援PyChecker提供的大部分功能,還有很多其 他的功能,如變數名是否符合指定的命名約定、你是否遵守了自己的編碼標準等。
安裝這些工具後,可以命令列指令碼的方式執行它們(PyChecker和PyLint對應的指令碼分別為 pychecker和pylint),也可將其作為Python模組(名稱與前面相同)。在Windows中,從命令列執行這兩個工具時,將分別使用批處理檔案pychecker.bat和 pylint.bat。因此,你可能需要將這兩個檔案加入環境變數PATH中,這樣才能從命令列執行 命令pychecker和pylint。
要使用PyChecker來檢查檔案,可執行這個指令碼並將檔名作為引數,如下所示:
pychecker file1.py file2.py ...
使用PyLint檢查檔案時,需要將模組(或包)名作為引數:
pylint module
PyChecker和PyLint都可作為模組(分別是pychecker.checker和pylint.lint)匯入,但它們 並不是為了以程式設計方式使用而設計的。匯入pychecker.checker時,它會檢查後續程式碼(包括匯入 的模組),並將警告列印到標準輸出。模組pylint.lint包含一個文件中沒有介紹的函式Run,這個 函式是供指令碼pylint本身使用的。
pychecker目前不支援python3.x。
pylint的使用很簡單,pylint目錄下(或設定系統路徑PATH)執行:
C:\Users\xx\AppData\Roaming\Python\Python37\Scripts>pylint manage.py
************* Module manage
manage.py:1:0: C0111: Missing module docstring (missing-docstring)
-----------------------------------
Your code has been rated at 8.89/10
C:\Users\zhx\AppData\Roaming\Python\Python37\Scripts>
就會看到其執行結果。
注:預設情況下pycharm預裝了pylint可以設定在選單tool下執行。進入PyCharm,從選單欄,依次進入: File -> Settings -> Tools -> External Tools。“+”,進行新增。需要填寫的部分分別是:“Name”,“Tool Settings -> Programs”、“Tool Settings -> Parameters”、“Tool Settings -> Working directory”。“Programs” 為pylint所在的目錄;Parameters 為$FilePath$即可在選單 Tools -> External Tools 中呼叫。
16.3.2 效能分析
標準庫包含一個卓越的效能分析模組profile,還有一個速度更快C語言版本,名為cProfile。 這個效能分析模組使用起來很簡單,只需呼叫其方法run並提供一個字串引數。
可以在cmd直接執行:
D:\>python -m cProfile test.py
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 test.py:1(<module>)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Prof
iler' objects}
D:\>
其中:“3 function calls in 0.000 seconds”是說呼叫了3個函式,用時0.00秒,其下為呼叫函式執行時間明細列表。
也可以引進入模組,形如:
#ptest.py
def foo():
sum = 0
for i in range(10000):
sum += i
sumA = bar()
sumB = bar()
return sum
def bar():
sum = 0
for i in range(100000):
sum += i
return sum
if __name__ == "__main__":
import cProfile
(待續)