返回文章列表

Python 程式碼測試與覆寫率分析

本文介紹如何使用 Pytest 框架進行 Python 程式碼測試,包含引數化測試的應用與程式碼覆寫率分析技巧,並說明如何使用 pytest-cov 工具計算程式碼覆寫率,以及如何撰寫有效的測試案例來提升程式碼品質。

軟體測試 Python

在 Python 開發中,確保程式碼品質至關重要,而測試是不可或缺的一環。本文將探討如何使用 Pytest 測試框架,包含引數化測試技巧,以及如何分析程式碼覆寫率,藉此提升測試的完整性和程式碼的可靠度。Pytest 提供了簡潔易用的語法和豐富的功能,讓撰寫測試案例更加輕鬆有效率。此外,pytest-cov 工具可以幫助我們計算程式碼覆寫率,找出未被測試覆寫到的程式碼區塊,進而完善測試案例,提升程式碼品質。透過引數化測試,我們可以更有效率地測試不同輸入值下的程式碼行為,減少重複的測試程式碼,並提高測試覆寫率。

測試與程式碼覆寫率

在軟體開發過程中,測試是確保程式碼品質的重要環節。Pytest 是一個流行的 Python 測試框架,提供了豐富的功能來幫助開發者撰寫和執行測試。本章節將介紹如何使用 Pytest 進行測試,以及如何評估測試的覆寫率。

引數化測試

引數化測試是一種測試方法,可以使用不同的輸入引數執行相同的測試函式,從而提高測試的效率和覆寫率。Pytest 提供了 @pytest.mark.parametrize 裝飾器來實作引數化測試。

import pytest

def is_even(n):
    return n % 2 == 0

@pytest.mark.parametrize("n, result", [
    (2, True),
    (3, False),
    (4, True)  # 此處故意設定錯誤的預期結果以示範錯誤訊息
])
def test_is_even(n, result):
    assert is_even(n) == result

內容解密:

  1. @pytest.mark.parametrize 用於定義多組輸入引數和預期結果,方便對同一個測試函式進行多次測試。
  2. test_is_even 函式會根據引數化的輸入執行多次測試。
  3. 當預期結果與實際結果不符時,Pytest 會提供詳細的錯誤訊息,指出哪一組引數的測試失敗。

程式碼覆寫率

程式碼覆寫率是用來衡量測試程式碼對原始程式碼的覆寫程度。常見的覆寫率指標包括行覆寫率和分支覆寫率。

行覆寫率

行覆寫率是指測試執行的程式碼行數佔總程式碼行數的比例。計算公式如下:

[ \text{coverage} = \frac{\text{lines executed}}{\text{total lines}} \times 100% ]

考慮以下範例程式碼:

def myfunc(x):
    if x > 0:
        print("x above threshold!")
        print("Running analysis.")
        y = round(x)
        z = y ** 2
    elif x < 0:
        z = abs(x)
    return z

如果我們撰寫以下測試:

def test_myfunc_1():
    assert myfunc(x=10.25) == 100

內容解密:

  1. test_myfunc_1 測試只涵蓋了 x > 0 的情況,因此只執行了部分程式碼。
  2. 行覆寫率的計算根據執行的程式碼行數,這可能受到程式碼結構的影響。

分支覆寫率

分支覆寫率是指測試涵蓋的程式碼分支數量佔總分支數量的比例。計算公式如下:

[ \text{coverage} = \frac{\text{branches executed}}{\text{total branches}} \times 100% ]

def myfunc(x):
    # Branch 1
    if x > 0:
        print("x above threshold!")
        print("Running analysis.")
        y = round(x)
        z = y ** 2
    # Branch 2
    elif x < 0:
        z = abs(x)
    return z

內容解密:

  1. 分支覆寫率關注於程式碼中的條件分支是否被測試到。
  2. 即使行覆寫率很高,如果某些關鍵分支未被測試到,仍然可能存在風險。

使用 Pytest-cov 計算覆寫率

Pytest-cov 是 Pytest 的一個擴充套件,用於計算程式碼覆寫率。首先,需要安裝 pytest-cov:

$ poetry add --dev pytest-cov

然後,可以使用以下命令計算覆寫率:

$ pytest tests/ --cov=pycounts

輸出結果將顯示各個模組的覆寫率情況,包括行數、未被執行的行數和覆寫率百分比。

內容解密:

  1. --cov=pycounts 指定要計算覆寫率的套件名稱。
  2. 輸出結果中,Stmts 表示模組中的程式碼行數,Miss 表示未被執行的行數,Cover 表示覆寫率百分比。

檔案撰寫與版本控制的重要性

在軟體開發過程中,測試和檔案撰寫是不可或缺的環節。本章節將延續前一章節的內容,探討如何使用 pytest 進行程式碼覆寫率測試,以及如何撰寫高品質的檔案。

使用 pytest 進行程式碼覆寫率測試

程式碼覆寫率測試是一種衡量測試完整性的指標,它能夠告訴我們有多少程式碼被測試所涵蓋。pytest-cov 是 pytest 的一個外掛,可以用來計算程式碼覆寫率。

分支覆寫率測試

分支覆寫率測試是檢查程式碼中的條件分支是否都被測試所涵蓋。可以使用 --cov-branch 引數來啟用分支覆寫率測試:

$ pytest --cov=pycounts --cov-branch

輸出結果將顯示每個模組的分支覆寫率:

Name                    Stmts   Miss Branch BrPart Cover
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
--
src/pycounts/__init__.py    2      0      0      0   100%
src/pycounts/data/__init__.py 0      0      0      0   100%
src/pycounts/datasets.py    5      0      0      0   100%
src/pycounts/plotting.py   12      0      2      0   100%
src/pycounts/pycounts.py   16      0      2      0   100%
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
--
TOTAL                      35      0      4      0   100%

程式碼覆寫率報告

pytest-cov 可以生成 HTML 格式的程式碼覆寫率報告,使用 --cov-report html 引數即可:

$ pytest --cov=pycounts --cov-report html

報告將儲存在 htmlcov/index.html,可以透過瀏覽器檢視詳細的程式碼覆寫率資訊。

版本控制

在開發過程中,版本控制是非常重要的。可以使用 Git 來管理程式碼的變更,並將變更推播到遠端儲存函式庫。

$ git add tests/test_pycounts.py
$ git commit -m "test: add additional tests for all modules"
$ git add src/pycounts/plotting.py
$ git commit -m "fix: check input type to plot_words function"
$ git push

檔案撰寫

檔案撰寫是軟體開發中非常重要的一環。良好的檔案可以幫助使用者瞭解如何使用軟體,並減少使用者的困惑。

檔案內容與流程

一般來說,Python 軟體包的檔案包括以下幾個部分:

檔名稱典型位置描述
README根目錄提供軟體包的簡介、安裝方法和使用方法
License根目錄說明軟體包的版權和授權資訊
Contributing guidelines根目錄說明如何參與軟體包的開發
Code of conduct根目錄定義參與軟體包開發的行為準則
Changelog根目錄紀錄軟體包的變更歷史
Docstrings.py 檔案中提供函式、類別和模組的說明和使用方法
Examplesdocs/ 目錄中提供使用軟體包的範例
API referencedocs/ 目錄中提供軟體包的 API 參考檔案

README 檔案

README 檔案是軟體包的簡介,通常包括軟體包的功能、安裝方法和使用方法。以下是一個範例:

# pycounts

Calculate word counts in a text file!

## Installation

```bash
$ pip install pycounts

Usage

pycounts can be used to count words in a text file and plot results as follows:

from pycounts.pycounts import count_words
from pycounts.plotting import plot_words
import matplotlib.pyplot as plt

file_path = "test.txt"  # path to your file
counts = count_words(file_path)
fig = plot_words(counts, n=10)
plt.show()

檔案撰寫流程

檔案撰寫流程通常包括以下幾個步驟:

  1. 編寫檔案:手動編寫檔案的原始檔案,通常使用 Markdown 或 reStructuredText 格式。
  2. 編譯檔案:使用工具將檔案的原始檔案編譯成 HTML 格式。
  3. 發布檔案:將編譯好的 HTML 檔案發布到網路上。

檔案的重要性

良好的檔案可以幫助使用者瞭解如何使用軟體,並減少使用者的困惑。同時,檔案也可以幫助開發者瞭解軟體的功能和使用方法,從而提高開發效率。

檔案撰寫與建置

檔案撰寫是軟體開發中不可或缺的一環,良好的檔案能夠幫助使用者快速理解和使用你的套件。本章節將介紹如何撰寫和建置檔案。

檔案撰寫流程

  1. 撰寫原始檔案:使用純文字標記語言,如 Markdown 或 reStructuredText,撰寫檔案內容。
  2. 建置檔案:使用檔案生成工具,如 sphinx,將原始檔案編譯成有組織、易於分享的格式,如 HTML 或 PDF。
  3. 線上託管檔案:使用免費服務,如 Read the Docs 或 GitHub Pages,將檔案分享到網路上,方便任何人存取。

撰寫檔案

下表列出了典型的套件檔案中包含的內容及其在套件目錄結構中的位置。大多數開發者使用範本來建立套件,這些範本通常會自動產生大部分的檔案。

常見檔案型別

  • README:套件的「地圖」,提供高階資訊,如套件功能、安裝方法、用法範例、作者資訊、授權條款和貢獻。
  • LICENSE:授權條款,說明他人可以使用和修改你的程式碼的條件。
  • CONTRIBUTING:貢獻,說明如何參與專案開發。
  • CONDUCT:行為準則,規範專案參與者的行為。

Markdown 語法範例

  • 標題使用井號(#)表示,井號數量對應標題層級。
  • 程式碼區塊使用三個反引號(```)包圍,後面可以接程式語言名稱以指定語法高亮。
  • 連結使用方括號([])包圍連結文字,後面接括號(())包圍的 URL。

README 範例

# pycounts
計算文字檔中的字數!

## 安裝
```bash
$ pip install pycounts

用法

pycounts 可以用來計算文字檔中的字數,並繪製結果:

from pycounts.pycounts import count_words
from pycounts.plotting import plot_words
import matplotlib.pyplot as plt

file_path = "test.txt"  # 你的檔案路徑
counts = count_words(file_path)
fig = plot_words(counts, n=10)
plt.show()

貢獻

有興趣貢獻?請檢視貢獻。請注意,本專案發布時附帶行為準則。參與本專案即表示您同意遵守其條款。

授權條款

pycounts 由 Tomas Beuzen 建立。根據 MIT 授權條款的條款進行授權。

製作人員

pycounts 使用 cookiecutterpy-pkgs-cookiecutter 範本 建立。


#### 內容解密:
1. **標題與段落**:使用 Markdown 的標題語法(#)來區分不同的段落,讓檔案結構清晰。
2. **程式碼區塊**:透過三個反引號(```)來定義程式碼區塊,並在後面標明程式語言,以實作語法高亮,使程式碼更易讀。
3. **連結語法**:使用方括號([])來定義連結文字,後接括號(())中的 URL,以建立超連結,方便讀者參考相關資源。
4. **貢獻與授權條款**:明確指出如何參與專案以及程式碼的授權方式,讓使用者和貢獻者瞭解相關規範。

### 建置與託管檔案

建置檔案需要使用工具如 sphinx,將 Markdown 或 reStructuredText 檔案轉換為 HTML 或 PDF 格式。接著,可以將建置好的檔案託管在 Read the Docs 或 GitHub Pages 等平台上,讓使用者可以輕鬆存取。

```plantuml
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Python 程式碼測試與覆寫率分析

package "軟體測試架構" {
    package "測試層級" {
        component [單元測試
Unit Test] as unit
        component [整合測試
Integration Test] as integration
        component [端對端測試
E2E Test] as e2e
    }

    package "測試類型" {
        component [功能測試] as functional
        component [效能測試] as performance
        component [安全測試] as security
    }

    package "工具框架" {
        component [pytest] as pytest
        component [unittest] as unittest
        component [Selenium] as selenium
        component [JMeter] as jmeter
    }
}

unit --> pytest : 撰寫測試
unit --> integration : 組合模組
integration --> e2e : 完整流程
functional --> selenium : UI 自動化
performance --> jmeter : 負載測試

note right of unit
  測試金字塔基礎
  快速回饋
  高覆蓋率
end note

@enduml

此圖示展示了檔案撰寫流程的主要步驟,從撰寫原始檔案到線上託管檔案的過程。

內容解密:

  1. 流程圖說明:此 Plantuml 圖表展示了檔案撰寫與建置的整體流程,從原始檔案的撰寫到最終的檔案線上託管,每一步驟環環相扣。
  2. 節點解釋
    • A[撰寫原始檔案]:使用 Markdown 等標記語言撰寫檔案的初始內容。
    • B[建置檔案]:利用 sphinx 等工具將原始檔案轉換為可視的 HTML 或 PDF 格式。
    • C[線上託管檔案]:將建置好的檔案上傳至 Read the Docs 或 GitHub Pages 等線上平台,便於使用者存取。
    • D[分享與協作]:透過線上託管的檔案,使用者可以方便地閱讀和參考,同時促進專案的分享與協作。

編寫檔案與貢獻

在開發Python套件的過程中,編寫完善的檔案與貢獻是至關重要的。這不僅能幫助使用者瞭解如何使用你的套件,也能促進社群對你的專案做出貢獻。

選擇合適的授權條款

選擇一個合適的授權條款對於開源專案來說是至關重要的。GitHub提供了一個有用的工具1來幫助你選擇最合適的授權條款。一些常見的Python套件授權條款包括:

  • Creative Commons CC0 1.0 Universal (CC0 1.0):將你的軟體釋放到公眾領域,讓他人可以無限制地使用。
  • MIT授權條款:允許使用者自由使用你的軟體,只要他們在任何副本或重大修改中包含原始的版權和授權宣告。
  • GNU General Public License v3 (GPL-3):相比上述授權條款,GPL-3的限制更多。任何對你的軟體所做的修改都必須被記錄下來,並且原始軟體和修改後的軟體的完整原始碼都必須在相同的GPL-3授權條款下提供。

如果沒有包含授權條款,預設的版權法則將適用,這通常意味著你保留了對原始碼的所有權利,任何人都不能下載、複製、分發或根據你的套件建立衍生作品。

貢獻

貢獻檔案(通常命名為“CONTRIBUTING”)概述了使用者如何為你的專案做出貢獻。這些會根據你如何與他人分享你的套件原始碼而有所不同,但通常包括你接受的貢獻型別以及如何做出這些貢獻(通常透過版本控制系統)。GitHub提供了一個很好的2來為你的專案新增貢獻檔案。

行為準則

行為準則檔案(通常命名為“CONDUCT”)用於定義社群標準,標識一個歡迎和包容的專案,並概述處理濫用行為的程式。GitHub提供了一個優秀的3來為你的專案新增行為準則。

更新日誌

更新日誌是一個包含按時間順序排列的對你的套件所做更改的檔案。更改通常按你的套件的已發布版本進行組織。擁有更新日誌有助於使用者和貢獻者瞭解套件的歷史以及它隨時間的演變。下面是一個假設的pycounts套件更新日誌的例子:

# 更新日誌
<!--next-version-placeholder-->

## v0.2.1 (2021年9月12日)

### 修復
- 更改了plotting.plot_words()中令人困惑的錯誤訊息

## v0.2.0 (2021年9月10日)

### 新增功能
- 為pycounts.count_words()增加了“stop_words”引數

### 檔案更新
- 增加了新的使用範例
- 現在在Read the Docs上託管檔案

## v0.1.0 (2021年8月24日)
- `pycounts`的第一個版本釋出

更新日誌解說:

  1. 版本資訊:每個版本都有明確的版本號和發布日期,方便追蹤變更。
  2. 變更類別:變更被分類別為「修復」、「新增功能」或「檔案更新」,便於理解變更性質。
  3. 變更描述:簡要描述每個變更,方便使用者快速瞭解變更內容。

使用範例

建立使用範例對於新舊使用者來說都是非常有價值的。與README中的簡短“用法”部分不同,這些範例更像是教程,包括文字、圖形和程式碼,以逐步演示你的套件的功能和常見工作流程。建議使用計算筆記本(如Jupyter Notebook)來建立範例。

範例創作:

  1. 針對不同使用者群體:為不同技能水平的使用者創作範例,從基礎到進階逐步引導。
  2. 使用計算筆記本:使用Jupyter Notebook等工具創作互動式範例,包括程式碼、公式、文字和視覺化內容。
  3. 逐步解說:詳細解釋每個範例步驟,讓讀者能夠理解並跟隨操作。