溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python第三方庫Coveralls

發(fā)布時間:2021-06-15 16:22:06 來源:億速云 閱讀:214 作者:chen 欄目:編程語言

本篇內容介紹了“python第三方庫Coveralls ”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前兩天在 GitHub 瀏覽 Python 的三方庫時,看到了以下

python第三方庫Coveralls

就像 https 那個綠色鎖的標志一樣,看著很可信,讓人用著放心,很多開源項目都有這些圖標。

看到 coverage 是 98%,我產生了疑問,這是手工統(tǒng)計的,還是程序自動測試出來的呢?

如果是手工統(tǒng)計的,肯定都往高了寫,這樣的數(shù)據(jù)也就沒有價值,如果是程序自動測試出來的,想著都覺得復雜,是怎么實現(xiàn)的呢?帶著這些疑問,我點擊了那個  coverage 98%,跳轉到了 https://coveralls.io/ 的頁面。

探索了一番,發(fā)現(xiàn)原來這是叫 coveralls 的三方庫實現(xiàn)的,用于在線實時顯示單元測試的覆蓋率,測試數(shù)據(jù)是通過 coverage 來跑出來的。

python第三方庫Coveralls

好奇的我 pip install 安裝了下,拿自己之前的程序,寫了幾個單元測試,用了下這兩條命令:

coverage run --source=dbinterface -m pytest tests/ coverage report -m

發(fā)現(xiàn),這個單元測試的覆蓋率果然是程序自動統(tǒng)計出來的,coverage 真的太牛了,有了這個,寫單元測試就無法偷懶了,代碼質量就有了量化標準。

python第三方庫Coveralls

從上面的圖中可以看到文件的哪些代碼行沒有測試到,然后針對性的編寫單元測試。還可以生成 html 文件進行查詢,更為直觀。

猜測 coverage 應該是記錄了 pytest  調用的代碼行數(shù),然后從全部代碼行記錄中去除已經(jīng)測試過的行記錄,就是未測試的代碼行,從而統(tǒng)計覆蓋率。

當時,我不由自主發(fā)出了‘臥槽牛批’,不過仍然有疑問,程序是怎么檢測哪些代碼行被執(zhí)行了呢?雖然我知道 debug  時可以看到,但是如何寫程序統(tǒng)計,我還一無所知。

好奇心驅使著我去探索。

首先看下這個 coverage 來自哪里,里面有什么內容:

(py38env) ? dbinterface git:(master) ? which coverage  /Users/aaron/py38env/bin/coverage

可以看到 coverage 的內容:

(py38env) ?  dbinterface git:(master) ? cat /Users/aaron/py38env/bin/coverage #!/Users/aaron/py38env/bin/python3 # -*- coding: utf-8 -*- import re import sys from coverage.cmdline import main if __name__ == '__main__':     sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])     sys.exit(main()) (py38env) ?  dbinterface git:(master) ?

其實,在命令行執(zhí)行 coverage,就相當于執(zhí)行:

/Users/aaron/py38env/bin/python3 coverage

將該文件保存到一個目錄中,命名為 main.py,然后使用 PyCharm IDE 開始調試,調試的過程中,發(fā)現(xiàn) coverage run  --source=dbinterface -m pytest tests/ 命令會將測試的結果寫入到文件 .coverage 中,再執(zhí)行 coverage  report -m 時會從該文件統(tǒng)計出覆蓋率。

也就是說關鍵是要弄清楚命令 coverage run --source=dbinterface -m pytest tests/ 的執(zhí)行過程。

繼續(xù) Debug,這里說下,由于我們的命令是在路徑 /Users/aaron/github/somenzz/dbinterface 下執(zhí)行的,在  Debug 前,先使用 os.chdir 改變程序的工作目錄:

main.py

#!/Users/aaron/py38env/bin/python3 # -*- coding: utf-8 -*- import re import sys from coverage.cmdline import main import os if __name__ == '__main__':     os.chdir('/Users/aaron/github/somenzz/dbinterface')     sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])     print(sys.argv[0])     sys.exit(main())

然后加入?yún)?shù),打好斷點,追蹤。

python第三方庫Coveralls

最后追蹤到這里:

python第三方庫Coveralls

這里的 tracer 類就是 CTracer,其源頭可以從 collector.py 文件的這段代碼看出來:

python第三方庫Coveralls

可以看出 tracer 的原型要么是 CTracer, 要么是 PyTracer。

從作者的注釋中可以看到 CTracer 速度非???,而 PyTracer 相對較慢。

python第三方庫Coveralls

想看 CTracer 的源代碼,結果發(fā)現(xiàn)了這個文件

python第三方庫Coveralls

.so 文件相當于 windows 的 dll  文件,是動態(tài)鏈接庫,需要反編譯成匯編語言,然后再分析執(zhí)行邏輯,這個對我來說太難了,自己又不熟悉匯編,于是放棄。

那就只剩下 PyTracer 了,原理應該是類似的,PyTracer 的源代碼就是 pytracer.py 文件,可以直接打開查看。

文件開始的地方,導入了以下三個庫:

import atexit import dis import sys  from coverage import env

其中前三個都是標準庫,atexit 是退出處理器,可以注冊一個函數(shù),在解釋器終止時執(zhí)行。dis 是 Python  字節(jié)碼反匯編器,這兩個的使用只有一次,沒有派上大用處,可以忽略。

重點就是第三個 sys 模塊,這個模塊和 os  模塊可以說是博大精深,很多程序都會使用到,從包的名稱也可以總結規(guī)律,名字越短,就越重要,其使用頻率就越高。

看 PyTracer 源代碼, sys.settrace 是起決定作用的,是 coverage 能夠統(tǒng)計單元測試覆蓋率的關鍵。

下面是對 Python 官方文檔對 sys.settrace 的介紹:

sys.settrace(tracefunc) 用來設置系統(tǒng)的跟蹤函數(shù),使得用戶在 Python 中就可以實現(xiàn) Python  源代碼調試器。該函數(shù)是特定于單個線程的,所以要讓調試器支持多線程,必須為正在調試的每個線程都用 settrace() 注冊一個跟蹤函數(shù),或使用  threading.settrace()。

跟蹤函數(shù)應接收三個參數(shù):frame、event 和 arg。frame 是當前的堆棧幀。event  是一個字符串:'call'、'line'、'return'、'exception' 或 'opcode'。arg 取決于事件類型。

官方文檔 bb 這么多,說實話我也沒太懂,到底咋用呢?我網(wǎng)上找了一個例子,比如說文件 trace.py 內容如下:

import sys  def stuff():     print("calling stuff")  def printer(frame, event, arg):     print(frame, event, arg)     return printer # return itself to keep tracing  sys.settrace(printer) stuff()

也就是說執(zhí)行函數(shù)之前,加上 sys.settrace。執(zhí)行該文件,可以得到以下結果:

(py38env) ?  tmp python trace.py <frame at 0x7fa6bff5a440, file 'trace.py', line 3, code stuff> call None <frame at 0x7fa6bff5a440, file 'trace.py', line 4, code stuff> line None calling stuff <frame at 0x7fa6bff5a440, file 'trace.py', line 4, code stuff> return None (py38env) ?  tmp

程序執(zhí)行的行數(shù),執(zhí)行的操作都完整的顯示了出來,將這些數(shù)據(jù)保存到文件中,就可以進行單元測試覆蓋率的統(tǒng)計了。

雖然無法方便的查詢 CTracer 源碼,但是從 PyTracer 這里還是學習到了 coverage 統(tǒng)計單元測試覆蓋率的統(tǒng)計方法。

一次偶遇 coveralls 讓我見識了 Python 原來還可以統(tǒng)計代碼的執(zhí)行情況,真的太秀了。

趁熱打鐵,我用 coveralls 的狀態(tài)圖標也發(fā)布了一個工具庫:dbinterface,單元測試覆蓋率 89%:

python第三方庫Coveralls

這個一個數(shù)據(jù)庫操作的通用接口,使用起來是相當?shù)暮唵?,從此讀寫各種數(shù)據(jù)庫都不是事:

from dbinterface.database_client import DataBaseClientFactory  client1 = DataBaseClientFactory.create(             dbtype="postgres",             host="localhost",             port=5432,             user="postgres",             pwd="121113",             database="postgres",         )  client2 = DataBaseClientFactory.create(             dbtype="mysql",             host="localhost",             port=3306,             user="aaron",             pwd="aaron",             database="information_schema",         )  result1 = client1.read("select current_date") rows_affeted = client1.write(     "insert into tmp_test_table values(%s, %s)", ("1", "aaron") ) rows_export = client.export(             "select * from information_schema.TABLES",             params=(),             file_path="/Users/aaron/tmp/mysql_tables.txt",             delimeter="0x02",             quote="0x03",             all_col_as_str=False,         )  assert rows_export > 0

“python第三方庫Coveralls ”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI