python自動化單元測試

python自動化單元測試

1. 前言

說實話,除了測試要求,我實在不知道寫單元測試有什麼意義,一個函數50行代碼,有多種參數組合,爲了測試這些條件,需要編寫測試用例,寫完的測試用例比需要測試的函數還長。也就是說,除了寫函數,還要寫測試用例,增加的工作量不是一點點。特別是,需求經常變化,維護功能性代碼本身就需要很大的工作量,還怎麼記得要同步更新測試用例呢?很多程序員連基本的註釋都做不好,還談什麼單元測試。

我不喜歡測試用例的另外一個原因,就是我們目前的代碼習慣是,除了基本的函數文檔外,還會在函數文檔中寫上一些測試用的數據,這些數據既是寫代碼時候的測試數據,也算是就針對這些數據寫代碼吧。

相比之下,我們的文檔和註釋已經很好了,有些人會說,良好的命名和代碼結構就能說明函數功能。我想說的是,啊呸,除了簡單到不行的功能,否則永遠是看註釋來的方便,註釋一行字,說明了業務功能和處理邏輯,而看代碼需要10行,還需要花心思理解其中的邏輯運算。爲什麼那麼多人喜歡造輪子,就是看不懂邏輯,但是知道要幹什麼,沒辦法,自己搞一套咯。

但是項目有要求,要有單元測試。沒辦法,請教測試組的同時有沒有辦法可以自動生成單元測試,得到的回答是,你好懶啊

2. 原理

用python的同學都是到函數文檔的個什麼東西,沒錯,我的想法就是在函數文檔中寫單元測試,另外用腳本提取函數文檔,生成單元測試文件,豈不快哉。

# -*- coding: utf-8 -*-
"""
python模塊的第一個註釋,就是模塊文檔,比如這一行
"""

def other_func(a,b):
    """函數的第一個註釋,就是函數文檔,比如這一行,當然也可以是多行"""
    pass

class maths():
    """類的第一個註釋,就是類文檔,比如這一行"""
    def __init__(self):
        pass

    def add(self, a,b):
        """類方法的第一個註釋,就是類方法的文檔,比如這一行"""
        pass

3. 單元測試的簡單類型

單元測試的簡單類型,包含以下幾個:
- 測試一個簡單函數,沒有外部依賴
- 測試一個簡單函數,包含外部函數依賴
- 測試一個簡單函數,包含外部類依賴
- 測試一個類方法,包含外部函數依賴
- 測試一個類方法,包含外部類依賴

爲什麼特別說明包含外部依賴呢?因爲我們寫代碼的時候,外部接口依賴說不定還沒有開始開發呢,而且開發了也不一定正確對吧,此時我們需要假設外部依賴已經完成並且是正確的,它會返回我們預期的值,這樣我們就可以接着往下寫代碼了。

這個假設,就是 mock,很有意思的東西。爲什麼簡單說明,請看下面的示例,我們需要調用外部http接口,但是http接口沒有完成,此時就假設它已經完成,並且返回值是10:

def get_http(url):
    return request(url)   # 正常的代碼,返回request的值
#--->
def get_http(url):
    return 10             # 測試時候,我們假設它返回10

在正式代碼中肯定是寫 request(url),但是在單元測試的代碼中,我們可以使用mock使它返回10.


@mock.patch('request')
def get_http(mock_request):
    mock_request.return_value = 10
    return request(url)    # 此時返回值是10,因爲我們用mock做了替換

4. 一個簡單的例子

下面的一段代碼是單元測試寫法,包含了mock函數和mock類方法:

import unittest
from unittest import mock

from unittest.pyauto_unittest_test import maths, func_add  # 導入需要測試的函數和類

class Test_pyauto_unittest_test(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):
        pass

    # 測試一個類的方法,沒有外部依賴
    def test_maths_add_0(self ,):
        a,b=1,2
        my_math = maths()
        result = my_math.add(a,b)
        self.assertEqual(result, 3)

    # 測試一個類的方法,並假設 self.add 的返回值是10
    def test_maths_add2_0(self ,):
        a,b=1,2
        my_math = maths()
        maths.add = mock.Mock(return_value = 10)  # 假設 self.add 的返回值是10
        result = my_math.add2(a,b)
        self.assertEqual(result, 10)

    # 測試一個類的方法,並假設調用外部函數的返回值是 10
    # 假設內部調用的類方法的返回值也是10 
    @mock.patch('unittest.pyauto_unittest_test.other_func')
    def test_maths_mul_0(self , mock_other_func):
        mock_other_func.return_value = 10   # 假設外部調用函數返回值是10 
        a,b=1,2
        my_math = maths()
        maths.add = mock.Mock(return_value = 10)  # 假設內部調用的類方法也是10
        result = my_math.mul(a,b)
        self.assertEqual(result, 20)

    # 測試一個函數,並假設內部調用的func_mul函數的返回值是10
    @mock.patch('unittest.pyauto_unittest_test.func_mul')
    def test_func_add_0(self , mock_func_mul):
        mock_func_mul.return_value = 10  # 假設內部調用的函數返回值是10
        a,b=1,2
        result = func_add(a,b)
        self.assertEqual(result, 20)

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

看到沒,這就是簡單的單元測試的寫法,已經涵蓋了大部分測試用例寫法。我們的目標,就是自動生成這樣的測試用例。

既然都是模板套出來的,就很簡單了。

5. 函數文檔格式要求

既然是要自動生成代碼,就需要事先約定格式要求,我們約定函數文檔如下:

class maths():
    def __init__(self):
        pass

    def add(self, a,b):
        """
        # 測試用例代碼需要夾在 兩個 === unittest === 之間
        === unittest ===   
        a,b=1,2                         # 一些初始化參數
        mock.Mock maths.add=10          # mock 類的方法,可以是外部調用的類
        mock.patch other_func=10        # mock 一個函數
        my_math = maths()               # 實例化當前類
        input = my_math.add(a,b)        # 輸入,即要測試的方法
        output = 3                      # 輸出,要進行assertEqual的值
        === unittest ===
        other unittest                  # 如果有多個測試,接着往下添加即可
        === unittest ===
        """
        return a+b

不管是測試函數還是測試類的方法啊,都以上面的格式約定規範化,是不是很簡答啊。
我們就根據這些文檔內容生成上面的測試用例,只要一一對應即可。

6. 生成測試用例

經過上面的講解說明,接下來要做的事情就很簡答了,包括遍歷整個項目的每一個python文件,遍歷每個模塊的函數和類方法,提取函數文檔,解析文檔內容,依照格式生成對應的測試用例文件即可。

代碼已經上傳到github,歡迎大家給個star。

7. 參考

Python單元測試unittest
python接口自動化測試(七)-unittest-批量用例管理
Python基礎-單元測試
python單元測試Mock總結
使用 Python Mock 類進行單元測試
https://www.cnblogs.com/fnng/p/5648247.html
Python 的模擬測試介紹
Python mock 使用心得
在Python中使用mock進行單元測試

python自動化單元測試首發於知乎專欄 從推公式到寫代碼CSDN博客

歡迎大家關注點贊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章