做者:HelloGitHub-追夢人物html
咱們完成了對 blog 應用和 comment 應用這兩個核心 app 的測試。如今咱們想知道的是究竟測試效果怎麼樣呢?測試充分嗎?測試全面嗎?還有沒有沒有測到的地方呢?python
單憑肉眼觀察難以回答上面的問題,接下來咱們就藉助 Coverage.py,從代碼覆蓋率的角度來檢測一下咱們的測試效果究竟如何。git
Coverage.py (如下簡稱 Coverage)是 Python 測試界最爲流行的一個庫之一,用來統計測試覆蓋率。測試覆蓋率能夠從一個角度衡量代碼的質量,覆蓋率越高,說明測試越充分,代碼出現 bug 的概率也就越小。固然須要注意的是,測試覆蓋率僅僅只是衡量代碼質量的一個角度,即便是 100% 的覆蓋率也不能說代碼就是完美的,沒有 bug 的。django
要使用 Coverage,首先固然是安裝它:編程
$ pipenv install coverage --dev
複製代碼
由於只在開發時才用獲得,因此使用 Pipenv 安裝時加 --dev 選項將其標記爲開發時的依賴庫。瀏覽器
Coverage 支持不少配置選項,爲了方便,一般將這些配置寫在名爲 .coveragerc
的文件中,Coverage 運行時會從項目根目錄讀取這個配置文件。所以先在項目根目錄建立這個文件並寫入最基本的配置:bash
[run]
branch = True
source = .
[report]
show_missing = True
複製代碼
Coverage 的配置遵循 ini 文件語法。簡單來講就是,[section]
表明一個配置塊,用於組織相關的一組配置。例如這裏 [run]
是一個配置塊,[report]
是另外一個配置塊,兩個塊下都有相關的一些配置項。微信
配置項的格式爲 key = value
。app
這幾個簡單配置項的含義爲:elasticsearch
branch = True
。是否統計條件語句的分支覆蓋狀況。if 條件語句中的判斷一般有 True 和 False 兩種狀況,設置 branch = True
後,Coverage 會測量這兩種狀況是否都被測試到。source = .
。指定需統計的源代碼目錄,這裏設置爲當前目錄(即項目根目錄)。show_missing = True
。在生成的統計報告中顯示未被測試覆蓋到的代碼行號。簡單配置後,咱們就能夠來運行 Coverage 了。
打開命令行,進入項目根目錄,依次運行下面的命令(注意若是沒有激活虛擬需使用 pipenv run 讓命令在虛擬環境中執行)。
首先運行 erase 命令清除上一次的統計信息
$ pipenv run coverage erase
複製代碼
manage.py test 運行 django 單元測試,這是這一次用 coverage run 來運行
$ pipenv run coverage run manage.py test
複製代碼
生成覆蓋率統計報告
$ pipenv run coverage report
複製代碼
覆蓋率統計報告輸出以下:
Name Stmts Miss Branch BrPart Cover Missing
--------------------------------------------------------------------------------------------
_credentials.py 2 2 0 0 0% 1-2
blog\__init__.py 0 0 0 0 100%
blog\admin.py 11 0 0 0 100%
blog\apps.py 4 0 0 0 100%
blog\elasticsearch2_ik_backend.py 8 0 0 0 100%
blog\feeds.py 12 0 0 0 100%
blog\migrations\0001_initial.py 7 0 0 0 100%
blog\migrations\0002_auto_20190711_1802.py 7 0 0 0 100%
blog\migrations\0003_auto_20191011_2326.py 4 0 0 0 100%
blog\migrations\0004_post_views.py 4 0 0 0 100%
blog\migrations\__init__.py 0 0 0 0 100%
blog\models.py 62 0 0 0 100%
blog\search_indexes.py 8 0 0 0 100%
blog\templatetags\__init__.py 0 0 0 0 100%
blog\templatetags\blog_extras.py 15 0 0 0 100%
blog\tests\__init__.py 0 0 0 0 100%
blog\tests\test_models.py 58 0 2 0 100%
blog\tests\test_smoke.py 4 0 0 0 100%
blog\tests\test_templatetags.py 115 0 2 0 100%
blog\tests\test_utils.py 11 0 0 0 100%
blog\tests\test_views.py 170 0 8 0 100%
blog\urls.py 4 0 0 0 100%
blog\utils.py 10 0 2 1 92% 14->16
blog\views.py 40 7 2 0 79% 64-72
blogproject\__init__.py 0 0 0 0 100%
blogproject\settings\__init__.py 0 0 0 0 100%
blogproject\settings\common.py 22 0 0 0 100%
blogproject\settings\local.py 5 0 0 0 100%
blogproject\settings\production.py 5 5 0 0 0% 1-8
blogproject\urls.py 4 0 0 0 100%
blogproject\wsgi.py 4 4 0 0 0% 10-16
comments\__init__.py 0 0 0 0 100%
comments\admin.py 6 0 0 0 100%
comments\apps.py 4 0 0 0 100%
comments\forms.py 6 0 0 0 100%
comments\migrations\0001_initial.py 7 0 0 0 100%
comments\migrations\0002_auto_20191011_2326.py 4 0 0 0 100%
comments\migrations\__init__.py 0 0 0 0 100%
comments\models.py 15 0 0 0 100%
comments\templatetags\__init__.py 0 0 0 0 100%
comments\templatetags\comments_extras.py 12 0 2 0 100%
comments\tests\__init__.py 0 0 0 0 100%
comments\tests\base.py 10 0 0 0 100%
comments\tests\test_models.py 8 0 0 0 100%
comments\tests\test_templatetags.py 57 0 6 0 100%
comments\tests\test_views.py 34 0 4 0 100%
comments\urls.py 4 0 0 0 100%
comments\views.py 17 0 2 0 100%
fabfile.py 21 21 0 0 0% 1-43
manage.py 12 2 2 1 79% 11-12, 20->exit
scripts\__init__.py 0 0 0 0 100%
scripts\fake.py 63 63 14 0 0% 1-106
--------------------------------------------------------------------------------------------
TOTAL 876 104 46 2 87%
複製代碼
倒數第二列是被統計文件的測試覆蓋率,第一列是未被覆蓋的代碼行號。
大部分文件測試覆蓋率爲 100%,說明咱們的測試仍是比較充分的。但從報告結果中咱們發現這樣幾個問題:
能夠經過添加 Coverage 配置項輕鬆解決上面 2 個問題。
在 [run]
配置塊中增長 omit
配置項能夠指定排除統計的文件。
在 [report]
配置塊中增長 skip_covered
配置項能夠指定統計報告中不顯示 100% 覆蓋的文件。
這是 .coveragerc
最終配置結果,注意咱們在 omit 配置項中指定忽略了一些非核心的項目文件:
[run]
branch = True
source = .
omit =
_credentials.py
manage.py
blogproject/settings/*
fabfile.py
scripts/fake.py
*/migrations/*
blogproject\wsgi.py
[report]
show_missing = True
skip_covered = True
複製代碼
再次按照上一節所說的方式運行 Coverage,最終報告結果以下:
Name Stmts Miss Branch BrPart Cover Missing
-----------------------------------------------------------
blog\utils.py 10 0 2 1 92% 14->16
blog\views.py 40 7 2 0 79% 64-72
-----------------------------------------------------------
TOTAL 709 7 30 1 99%
33 files skipped due to complete coverage.
複製代碼
這個報告指出咱們仍有 2 個文件沒有達到 100% 的覆蓋率,咱們要作的就是爲這兩個文件中未測試的代碼增長單元測試,讓其達到 100% 測試覆蓋率。
不過在動手寫測試以前,咱們要搞清楚哪些代碼沒被測到。命令行報告的最後一列指出了未被測試代碼的行號,可是這樣看着不是很直觀。一種體驗更好的方式是生成 HTML 報告,這樣咱們能夠直接在 HTML 報告中查看到未被測試到的具體代碼。
coverage report
命令在命令行生成統計報告,而 coverage html
則能夠生成 HTML 報告。
在上一節的基礎上,運行以下命令:
$ pipenv run coverage html
複製代碼
運行完成後項目根目錄會多出一個 htmlcov 的文件夾,裏面就是測試覆蓋率的 HTML 報告文件。用瀏覽器打開裏面的 index.html 文件就能夠查看報告結果了:
主頁和命令行的結果是同樣的,不過咱們能夠點擊文件名,進入到對這個文件更加具體的統計報告頁面,例如 blog\views.py 結果以下:
綠色部分表明已覆蓋的代碼,紅色部分表明爲覆蓋的代碼。
查看文件咱們發現,blog\views.py 中未被覆蓋的代碼原來是 Django 博客實現簡單的全文搜索 中的代碼,如今咱們已經將搜索替換爲 Django Haystack 全文檢索 了,這段代碼也就不須要了,能夠直接刪除。
blog\views.py 的報告結果則代表咱們在 Django Haystack 全文檢索與關鍵詞高亮 中自定義的搜索關鍵詞高亮器有一個 if 分支條件未被測試到:
檢查 blog/tests/test_utils.py 中的測試用例,咱們發現只測試了比較短的標題不被截斷,也就是
if len(text_block) < self.max_length:
複製代碼
判斷條件爲 True,缺失對判斷條件爲 False 的測試。因此咱們來構造一個新的測試用例測試標題長度超過 max_length
(默認值爲 200)的狀況時會被截斷:
class HighlighterTestCase(TestCase):
def test_highlight(self):
# 省略已有代碼 ...
highlighter = Highlighter("標題")
document = "這是一個長度超過 200 的標題,應該被截斷。" + "HelloDjangoTutorial" * 200
self.assertTrue(
highlighter.highlight(document).startswith(
'...<span class="highlighted">標題</span>,應該被截斷。'
)
)
複製代碼
再次運行 Coverage 生成報告,測試覆蓋率全都 100% 了!
$ pipenv run coverage erase
$ pipenv run coverage run manage.py test
$ pipenv run coverage report
# 輸出
Name Stmts Miss Branch BrPart Cover Missing
---------------------------------------------------
---------------------------------------------------
TOTAL 704 0 28 0 100%
複製代碼
最後提醒一點,Coverage 運行後可能會在項目目錄下生成一些文件,這些文件並不須要歸入版本管理,因此將其加入 .gitignore 文件中,防止被提交到代碼庫:
htmlcov/
.coverage
.coverage.*
coverage.xml
*.cover
複製代碼
『講解開源項目系列』——讓對開源項目感興趣的人再也不畏懼、讓開源項目的發起者再也不孤單。跟着咱們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎聯繫我(微信:xueweihan,備註:講解)加入咱們,讓更多人愛上開源、貢獻開源~