日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

第十六章 测试基础

發布時間:2023/12/1 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第十六章 测试基础 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第十六章 測試基礎

在編譯型語言中,需要不斷重復編輯、編譯、運行的循環。
在Python中,不存在編譯階段只有編輯和運行階段。測試就是運行程序

先測試再編碼

極限編程先鋒引入了“測試一點點,再編寫一點點代碼”的理念。
換而言之,測試在先,編碼在后。這也稱為測試驅動的編程。

準確的需求說明

要闡明程序的目標,可編寫需求說明,也就是描述程序必須滿足何種需求的文檔(或便條)。
測試程序就是需求說明,可幫助確保程序開發過程緊扣這些需求。

假設你要編寫一個模塊,其中只包含一個根據矩形的寬度和高度計算面積的函數。動手編寫代碼前,編寫一個單元測試,其中包含一些你知道答案的例子。

文件area.py內容如下:

def rect_area(height,width):return height*height #很顯然不對

同目錄下的test.py內容如下:

from area import rect_area height = 3 width = 4 correct_answer = 12 answer = rect_area(height,width) if answer == correct_answer:print('Test passed') else:print('Test failed')''' 很顯然,輸出結果為:Test failed 接下來,你可能檢查代碼,看看問題出在什么地方,并將返回的表達式替換為height * width。 '''

做好應對變化的準備

自動化測試不僅可在你編寫程序時提供極大的幫助,還有助于在你修改代碼時避免累積錯誤,這在程序規模很大時尤其重要。

代碼覆蓋率
覆蓋率(coverage)是一個重要的測試概念。運行測試時,很可能達不到運行所有代碼的理想狀態。(實際上,最理想的情況是,使用各種可能的輸入檢查每種可能的程序狀態,但這根本不可能做到。)優秀測試套件的目標之一是確保較高的覆蓋率,為此可使用覆蓋率工具,它們測量測試期間實際運行的代碼所占的比例。
Python自帶的程序trace.py。
要確保較高的測試覆蓋率,方法之一是秉承測試驅動開發的理念。只要能確保先編寫測試再編寫函數,就能肯定每個函數都是經過測試的。

測試四部曲

1,確定需要實現的新功能。可將其記錄下來,再為之編寫一個測試。
2,編寫實現功能的框架代碼,讓程序能夠運行(不存在語法錯誤之類的問題),但測試依然無法通過。
3, 編寫讓測試剛好能夠通過的代碼。
4,改進(重構)代碼以全面而準確地實現所需的功能,同時確保測試依然能夠成功。

測試工具

doctest

文件my_math.py

def square(x):return x * xif name == '__main__':import doctest, my_mathdoctest.testmod(my_math)

對模塊doctest中的函數testmod進行測試
python my_math.py
先顯然,并沒有什么顯示輸出
函數doctest.testmod讀取模塊中的所有文檔字符串,查找看起來像是從交互式解釋器中摘取的示例,再檢查這些示例是否反映了實際情況。

為獲得更多的輸出,可在運行腳本時指定開關-v(verbose,意為詳盡)。
python my_math.py -v
輸入如下:

Running my_math.__doc__ 0 of 0 examples failed in my_math.__doc__ Running my_math.square.__doc__ Trying: square(2) Expecting: 4 Ok Trying: square(3) Expecting: 9 ok 0 of 2 examples failed in my_math.square.__doc__ 1 items had no tests: test 1 items passed all tests: 2 tests in my_math.square 2 tests in 2 items. 2 passed and 0 failed. Test passed.

假設要使用Python冪運算符而不是乘法運算符,將x * x替換為x ** 2,再運行腳本對代碼進行測試。
輸出如下:

***************************************************************** Failure in example: square(3) from line #5 of my_math.square Expected: 9 Got: 27 ***************************************************************** 1 items had failures: 1 of 2 in my_math.square ***Test Failed*** 1 failures.

unittest

doctest使用起來很容易,但unittest(基于流行的Java測試框架JUnit)更靈活、更強大。

一個使用框架unittest的簡單測試

import unittest, my_math class ProductTestCase(unittest.TestCase):def test_integers(self):for x in range(-10, 10):for y in range(-10, 10):p = my_math.product(x, y)self.assertEqual(p, x * y, 'Integer multiplication failed')def test_floats(self):for x in range(-10, 10):for y in range(-10, 10):x = x / 10y = y / 10p = my_math.product(x, y)self.assertEqual(p, x * y, 'Float multiplication failed')if __name__ == '__main__': unittest.main()

運行這個測試腳本將引發異常,指出模塊my_math不存在。

模塊unittest區分錯誤和失敗。錯誤指的是引發了異常,而失敗是調用failUnless等方法的結果。

文件my_math.py

def product(x,y):pass#框架代碼,沒什么意思。

運行前面的測試,將出現兩條FAIL消息,輸出如下:

FF ====================================================================== FAIL: test_floats (__main__.ProductTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_my_math.py", line 17, in testFloats self.assertEqual(p, x * y, 'Float multiplication failed') AssertionError: Float multiplication failed ====================================================================== FAIL: test_integers (__main__.ProductTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_my_math.py", line 9, in testIntegers self.assertEqual(p, x * y, 'Integer multiplication failed') AssertionError: Integer multiplication failed ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (failures=2)

開頭兩個字符,兩個F,表示兩次失敗。

接下來需要讓代碼管用。修改文件my_math.py

def product(x,y):return x * y

再次運行前面的測試,輸出如下:

.. ---------------------------------------------------------------------- Ran 2 tests in 0.015s OK

開頭的兩個句點表示測試。

再次修改函數product,即修改文件my_math.py

def product(x, y):if x == 7 and y == 9:return 'An insidious bug has surfaced!'else:return x * y

再次運行前面的測試腳本,將有一個測試失敗。輸出如下:

.F ====================================================================== FAIL: test_integers (__main__.ProductTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_my_math.py", line 9, in testIntegers self.assertEqual(p, x * y, 'Integer multiplication failed') AssertionError: Integer multiplication failed ---------------------------------------------------------------------- Ran 2 tests in 0.005s FAILED (failures=1)

超越單元測試

兩個工具:源代碼檢查和性能分析。
源代碼檢查是一種發現代碼中常見錯誤或問題的方式(有點像靜態類型語言中編譯器的作用,但做的事情要多得多)。
性能分析指的是搞清楚程序的運行速度到底有多快。

使用PyChecker 和 PyLint 檢查源代碼

PyChecker(pychecker.sf.net)用于檢查Python源代碼的唯一工具,能夠找出諸如給函數提供的參數不對等錯誤。
標準庫中還有tabnanny,但沒那么強大,只檢查縮進是否正確。

之后出現了PyLint(pylint.org),它支持PyChecker提供的大部分功能,還有很多其他的功能,如變量名是否符合指定的命名約定、是否遵守了自己的編碼標準等。

使用Distutils來安裝,可使用如下標準命令。
python setup.py install
PyLint,也可使用pip來安裝。

使用PyChecker來檢查文件,可運行這個腳本并將文件名作為參數
pychecker file1.py file2.py ...

使用PyLint檢查文件時,需要將模塊(或包)名作為參數:pylint module

PyChecker和PyLint都可作為模塊(分別是pychecker.checker和pylint.lint)導入

導入pychecker.checker時,它會檢查后續代碼(包括導入的模塊),并將警告打印到標準輸出。

模塊pylint.lint包含一個文檔中沒有介紹的函數Run,這個函數是供腳本pylint本身使用的。它也將警告打印出來,而不是以某種方式將其返回。

使用模塊subprocess調用外部檢查器

import unittest, my_math from subprocess import Popen, PIPEclass ProductTestCase(unittest.TestCase):def test_with_PyChecker(self):cmd = 'pychecker', '-Q', my_math.__file__.rstrip('c')pychecker = Popen(cmd, stdout=PIPE, stderr=PIPE)self.assertEqual(pychecker.stdout.read(), '')def test_with_PyLint(self):cmd = 'pylint', '-rn', 'my_math'pylint = Popen(cmd, stdout=PIPE, stderr=PIPE)self.assertEqual(pylint.stdout.read(), '')if __name__ == '__main__': unittest.main()

對于pychecker,開關-Q(quiet,意為靜默);
對于pylint,開關-rn(其中n表示no)以關閉報告,這意味著將只顯示警告和錯誤。

命令pylint直接將模塊名作為參數
讓pychecker正確地運行,需要獲取文件名。使用了模塊my_math的屬性__file__,并使用rstrip將文件名末尾可能包含的c刪掉(因為模塊可能存儲在.pyc文件中)

模塊my_math,文件my_math.py

__revision__ = '0.1' def product(factor1, factor2):'The product of two numbers'return factor1 * factor2

性能分析

在編程中,不成熟的優化是萬惡之源。
如果程序的速度達不到你的要求,必須優化,就必須首先對其進行性能分析。

標準庫包含一個卓越的性能分析模塊profile,還有一個速度更快C語言版本,名為cProfile。
這個性能分析模塊使用起來很簡單,只需調用其方法run并提供一個字符串參數。
這里照樣使用了以前的文件my_math.py

import cProfile from my_math import product cProfile.run('product(1, 2)')

這將輸出如下信息:各個函數和方法被調用多少次以及執行它們花費了多長時間。如果通過第二個參數向run提供一個文件名(如’my_math.profile’),分析結果將保存到這個文件中。然后,就可使用模塊pstats來研究分析結果了。

import pstats p = pstats.Stats('my_math.profile')

小結

概念描述
測試驅動編程大致而言,測試驅動編程意味著先測試再編碼。有了測試,就能信心滿滿地修改代碼,這讓開發和維護工作更加靈活。
模塊doctest和unittest需要在Python中進行單元測試時,這些工具必不可少。模塊doctest設計用于檢查文檔字符串中的示例,但也可輕松地使用它來設計測試套件。為讓測試套件更靈活、結構化程度更高,框架unittest很有幫助。
PyChecker和PyLint這兩個工具查看源代碼并指出潛在(和實際)的問題。它們檢查代碼的方方面面——從變量名太短到永遠不會執行的代碼段。只需編寫少量的代碼,就可將它們加入測試套件,從而確保所有修改和重構都遵循了你采用的編碼標準。
性能分析如果很在乎速度,并想對程序進行優化(僅當絕對必要時才這樣做),應首先進行性能分析:使用模塊profile或cProfile來找出代碼中的瓶頸。

本章介紹的新函數

函數描述
doctest.testmod(module)檢查文檔字符串中的示例(還接受很多其他的參數)
unittest.main()運行當前模塊中的單元測試
profile.run(stmt[,filename])執行語句并對其進行性能分析;可將分析結果保存到參數filename指定的文件中

總結

以上是生活随笔為你收集整理的第十六章 测试基础的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。