如何測試代碼覆蓋率:coverage.py 簡介

BlyOrdell 8年前發布 | 10K 次閱讀 Python Python開發

本文作者為 Mike Driscoll,譯者為 linkcheng,校對 EarlGrey,是 Python 翻譯組完成的第二篇譯文。本文為編程派微信公眾號首發。

Coverage.py是一個用來測試代碼覆蓋率的 Python 第三方庫。它起初是由 Ned Batchelder 創建。在編程界,術語“覆蓋”通常是用來描述測試的有效性,以及測試的實際覆蓋率。coverage.py 庫支持 Python 2.6 或者更高的版本,還兼容 Python 3 的最新版以及 PyPy 。

pip install coverage

執行以上指令來安裝 coverage.py ,不過我們需要寫一些代碼才能使用它。創建一個名為 mymath.py 的模塊,代碼如下:

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(numerator, denominator):
    return float(numerator) / denominator

現在需要一個測試文件。接下來,我們創建一個測試 add 函數的測試文件,并將其命令為 test_mymath.py 。然后把它保存在與 mymath.py 的相同目錄下。接著在測試文件中寫入以下代碼:

# test_mymath.py
import mymath
import unittest

class TestAdd(unittest.TestCase):
    """
    Test the add function from the mymath library
    """

    def test_add_integers(self):
        """
        Test that the addition of two integers returns the correct total
        """
        result = mymath.add(1, 2)
        self.assertEqual(result, 3)

    def test_add_floats(self):
        """
        Test that the addition of two floats returns the correct result
        """
        result = mymath.add(10.5, 2)
        self.assertEqual(result, 12.5)

    def test_add_strings(self):
        """
        Test the addition of two strings returns the two string as one
        concatenated string
        """
        result = mymath.add('abc', 'def')
        self.assertEqual(result, 'abcdef')


if __name__ == '__main__':
    unittest.main()

一切準備就緒,讓我們使用測試文件來運行 coverage.py。打開終端并且進入我們剛才寫的那兩個文件所在的目錄。然后通過以下方式執行 coverage.py:

coverage run test_mymath.py

注意,我們需要調用 run 才能讓 coverage.py 運行指定的模塊。如果模塊接收參數,可以像正常運行這個的模塊一樣帶上參數。當執行以上指令后,你會看到測試模塊的輸出,就像正常運行該模塊一樣。在當前目錄下,你還會發現一個名字為 .coverage 的文件(注意開頭的點號)。要想獲得文件中的信息,需要執行以下指令:

coverage report -m

執行這條指令將會在終端打印以下信息:

Name             Stmts   Miss  Cover   Missing
----------------------------------------------
mymath.py            9      3    67%   9, 13, 17
test_mymath.py      14      0   100%
----------------------------------------------
TOTAL

-m選項告訴 coverage.py 你想在輸出信息中顯示 Missing 列。如果省略 -m 選項,就只能看到前四列信息。上面的輸出表明,coverage 在執行完測試代碼之后,判斷我寫的單體測試程序對 mymath 模塊的覆蓋率只有 67% 。 “Missing” 列表明哪些行代碼沒有被覆蓋。如果你看過 coverage.py 指出的那些行代碼,很快就會發現測試程序沒有運行測試 subtract , multiplydivide 函數。

在嘗試添加更多的覆蓋率測試代碼之前,先來學習一下怎么通過 coverage.py 來生成 HTML報告。只需要執行以下命令即可:

coverage html

以上指令將會生成一個叫 htmlcov 的目錄,其中包括各種各樣的文件。進入這個目錄,并通過瀏覽器打開 index.html 文件。在我的電腦上,瀏覽器加載了這樣的頁面:

實際上,你可以通過點擊 Module 列中列出的文件名來打開一個新的頁面,頁面中將會明顯標識出代碼中沒有被單體覆蓋的部分。顯然 mymath.py 的覆蓋率不夠高,所以點擊 mymath.py ,頁面最終顯示如下:

以上截圖清晰地展示了沒有被單體測試所覆蓋的部分。現在我們清楚地知道測試覆蓋有哪些缺失了,接下來就給 subtract 函數添加單體測試,并且看一下覆蓋率的改變。

打開 test_mymath.py 并且添加下邊的類:

class TestSubtract(unittest.TestCase):
    """
    Test the subtract function from the mymath library
    """

    def test_subtract_integers(self):
        """
        Test that subtracting integers returns the correct result
        """
        result = mymath.subtract(10, 8)
        self.assertEqual(result, 2)

現在我們需要重新對更新后的測試文件運行 coverage。你只需要再次運行該命令即可: coverage run test_mymath.py 。命令輸出將指出成功通過了四個測試。接著,重新運行 coverage html ,再打開 index.html 文件。你應該會看到我們達到了 78% 的覆蓋率:

這次修改讓覆蓋率提高了 11% !接下來,讓我們給 multiply 和 divide 函數添加簡單的測試,看覆蓋率能否達到 100% !

class TestMultiply(unittest.TestCase):
    """
    Test the multiply function from the mymath library
    """

    def test_subtract_integers(self):
        """
        Test that multiplying integers returns the correct result
        """
        result = mymath.multiply(5, 50)
        self.assertEqual(result, 250)


class TestDivide(unittest.TestCase):
    """
    Test the divide function from the mymath library
    """

    def test_divide_by_zero(self):
        """
        Test that multiplying integers returns the correct result
        """
        with self.assertRaises(ZeroDivisionError):
            result = mymath.divide(8, 0)

再次運行之前運行過的命令,然后再重新打開 “index.html”。然后就會看到如下截圖:

正如你看到的那樣,這次我們的覆蓋率達到了 100%!顯然,覆蓋率 100% 意味著我們測試程序測試了每一個需要被測試的函數。當然這也有些不盡人意的地方,比如:add 函數的單體測試數量是其他幾個函數的三倍,然而 coverage.py 并沒有給出關于這些的詳細信息。盡管 coverage.py 不能詳盡說明我們是否測試了所有可能的參數組合情況,但卻可以明確反映關于覆蓋率的一些基本信息。

額外信息

順便再簡單提及一些 coverage.py 的其他特性。首先,coverage.py 支持配置文件。配置文件格式是傳統的“.ini”文件,使用中括號作為節與節的分界(例如:[my_section])。還可以使用 # 或者 ; (分號)來添加注釋。

Coverage.py 也允許在上述提到的配置文件中指定你需要解析的源文件。一旦在配置文件中設置了需要解析的文件,就可以通過運行 coverage.py 來看運行結果。它還支持“-source”命令行選項。最后,還可以使用“-include”和“-omit”選項來包含或者移除一個文件名模式的列表。這些選項也可以通過在配置文件中添加對應的配置項進行設置。

關于 coverage.py 想最后再說明一點,就是它支持插件。你可以自己寫插件,也可以從網上下載并安裝別人的插件來增強 coverage.py 的功能。

總結

現在你已經了解 coverage.py 的基本情況以及它的一些用途。Coverage.py 可以檢測單體測試代碼并且發現單體測試覆蓋中的漏洞。如果不確定你的單體測試程序是否達標,那么使用這個庫包將會幫助你找到那些存在的漏洞。即便如此,你仍然需要認真負責地編寫高質量的測試程序。如果沒有寫出有效的測試,而且測試還通過了,那么 coverage.py 也無法幫到你。

點此查看原文鏈接

Python 翻譯組 是EarlGrey@編程派發起成立的一個專注于 Python 技術內容翻譯的小組,目前已有近 30 名 Python 技術愛好者加入。

 

來自:http://www.codingpy.com/article/an-intro-to-coveragepy/

 

 本文由用戶 BlyOrdell 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!