1、引言
我有一個朋友是做 Python 自動化測試的。前幾天他告訴我去參加一個大廠面試被刷了。
我問他是有沒有總結被刷下來的原因。他說面試官問了一些 pytest 單元測試框架相關的知識,包括什么插件系統和用力篩選。但是他所在的公司用的技術是基于 unittest 的,沒有用過 pytest。
我跟他說你可以和技術面試官說明,在實際過程當中你沒有使用過 pytest,但是你可以后面再學。這哥們說:我就是這樣跟面試官說的,但是面試官告訴我 pytest 現在已經是行業里面的主流,還在堅持用 unittest 說明我的技術已經過時了,沒有跟上現在測試領域的發展。
實際上他在面試之前已經了解過 pytest 的一些基礎用法,但是網上的一些資料,都是停留在用法和一些知識點的講解,沒有深入到 pytest 內部運行和一些高級特性。所以被問到的時候,自己臨時抱佛腳的一些知識都沒有用上。
后面我給這位朋友補習了一些關于 Python 的高級特性。現在我連同基礎部分的內容一起貼出來,希望對 Python 自動化測試的一些朋友有所幫助。
2、為什么用單元測試框架?
首先我要說明一下什么是單元測試框架?
unittest 和 pytest 都是單元測試框架。單元測試指的是在編程過程當中形成的對函數或者是類下面的方法進行測試的一個過程。
在不使用任何框架的前提下,其實也是可以進行單元測試的。比如我們可以通過 if 判斷
、異常處理或者是其他的流程控制來表示測試是否通過。
def add(a, b):return a + bdef test_add():ret = add(3, 4)if ret == 7:print("add 函數的測試通過")else:print("add 函數的測試失敗")
如果要運行這個用例,需要手工調用 test_add 這個函數:
test_add()
接下來,使用 python 運行這個文件,就能得到測試結果:
python test_add.py
雖然說上面我們通過 if 判斷,對一個函數進行了測試,而且得到了測試結果,但是流程是比較復雜的:
- 首先我們需要人工去判斷結果,
- 第 2 我們需要通過 Python 去運行模塊。
- 第 3,我們還需要顯性的去調用 test_add 這個函數。
這還只是在我們只測試了一個函數的情況下,當需要測試的函數或者類越來越多的時候,這個過程會越來越復雜。
而使用單元測試框架,可以極大的簡化我們對單元測試的過程,使用單元測試框架以后,框架會幫我們自動去收集用例、運行用例、生成報告。
?
3、pytest 的基礎使用
上面的測試代碼使用 pytest 編寫,可以這樣寫。
def add(a, b):return a + bdef test_add():assert 7 == add(3,4)
寫完測試用例以后,我們只需要在目錄下輸入 pytest 指令,就可以自動運行用例,而且呢結果會直接顯示在命令行的下方。
上面講的是單元測試過程,也就是說對某個函數或者是類下面的方法進行測試,有的人可能會不理解。在實際工作過程當中很少進行單元測試啊,測試人員做的更多的是接口測試,UI 測試,pytest 怎么用呢?
實際上不管是接口測試還是 UI 測試,都是可以使用 pytest。當你進行接口測試的時候,你只需要把訪問接口的過程封裝成一個 Python 函數。
def visit_api():print("訪問接口,得到結果...")return responsedef test_api():assert expected_response == visit_api()
當你進行 Web 測試的時候,你只需要操作瀏覽器的過程封裝成一個函數?
def browser_method():print("點點點")return ui_responsedef test_web():assert expected_response == browser_method()
在這種情況下。接口訪問和 Web 操作都是以函數形式存在的,我們直接去測試這個 Python 函數,也是一個單元測試的過程。
因為 pytest 是一個第三方的框架,所以我們先要安裝。安裝方式非常簡單,只需要通過 pip 這個包管理工具安裝就可以了。
pip install -U pytest
安裝完成以后,我們可以向使用上面的那個例子一樣:
- 第 1 步:定義一個測試函數,這個測試函數通常會調用被測函數。
- 第 2 步:使用 assert 斷言,assert 后面可以跟任意的 Python 條件表達式。
assert 4 < 5assert "yuze" in "yuze wang"assert isinstance(6, int)
測試用例函數有 2 個注意事項:
- 函數名稱以 test_ 開頭;
- 保存測試用例的文件以 test_*.py 的形式或者 *_test.py 的形式。
例行用了以后呢,在命令行當中會顯示 4 個部分的內容:
- 第 1 個部分,測試用例和通過的結果,
- 第 2 個部分,失敗用例回溯信息,
- 第 3 個部分,輸出捕獲信息,
- 第 4 個部分,總結信息。
在拍 test 當中通過的測試用例,不會有特別詳細的結果,但是這是失敗的測試用例默認會有非常詳細的結果,而且會幫你捕獲錯誤原因。?
?現在我也找了很多測試的朋友,做了一個分享技術的交流群,共享了很多我們收集的技術文檔和視頻教程。
如果你不想再體驗自學時找不到資源,沒人解答問題,堅持幾天便放棄的感受
可以加入我們一起交流。而且還有很多在自動化,性能,安全,測試開發等等方面有一定建樹的技術大牛
分享他們的經驗,還會分享很多直播講座和技術沙龍
可以免費學習!劃重點!開源的!!!
qq群號:485187702【暗號:csdn11】
4、測試夾具(Fixture)是什么?
在測試過程當中,有時你需要提前給你的測試用例去準備一個運行環境。這個測試環境通常來說被稱為測試夾具(Fixture),又被稱為固定裝置、測試固件等。
作者:小溪流
鏈接:https://www.zhihu.com/question/50182320/answer/2293584521
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
?
- 當你要測試一個電器的時候,你需要提供不同的輸入電壓電流的環境,
- 當你測試一臺電腦網絡的時候,必須要提供網絡環境,
- 當你要測試一個手機游戲能否被安裝時,你需要提供一臺手機環境,
- 當你要測試一個軟件能否登錄的時候,你需要準備用戶名和密碼這樣的用戶環境,
- 當你要測試一個數據庫能否操作的時候,需要提供數據庫的連接環境。
現在我們來舉一個夾具的例子,我們需要測試一個注冊的函數。這個注冊函數提供兩個參數,第 1 個參數是手機號,第 2 個參數是密碼。注冊函數的邏輯就是對手機號碼和密碼進行校驗,如果通過校驗表示注冊成功,如果不通過表示注冊失敗。
def is_mobile(number: str):if re.search(r"^1[3-9][0-9]{9}$", number):return Truereturn Falsedef register(mobile, password):if is_mobile(mobile) and len(password) >= 6:return "success"return "fail"def test_register():assert "success" == register("13177778888", "123456")
這個測試用例并沒有什么問題,但是它存在優化的空間。一個優化的空間是每個手機號碼都是我們手工生成的,當需要編寫多組數據測試時,會有一點費時間。現在我們可以編寫一個函數,自動生成一個手機號碼,當我有多組數據需要測試的時候,我只需要重復調用生成手機號碼的函數,就可以獲取測試數據。這個生成手機號碼的函數呢,就是一個夾具。
def gen_a_mobile():"""隨機生成 13 開頭的手機號碼。"""random_num = "".join([str(random.randint(1,9)) for i in range(9)])return "".join(["13", random_num])
pytest 提供了一種叫做依賴注入的機制,當一個函數被聲明為夾具的時候,可以在測試函數中傳入這個夾具的名稱,pytest 會自動調用它。
import randomimport pytest@pytest.fixturedef gen_a_mobile():"""隨機生成 13 開頭的手機號碼。"""random_num = "".join([str(random.randint(1,9)) for i in range(9)])return "".join(["13", random_num])def test_register(gen_a_mobile):assert "success" == register(gen_a_mobile, "123456")
pytest 當中的夾具系統非常非常的靈活,后面如果有時間的我專門寫文章跟大家講解夾具系統。
5、數據驅動和參數化
現在我們編寫的函數和測試用例是 1 對 1 的關系,也就是說,當你想測試某個功能場景的時候,你必須要去編寫一個對應的測試函數。當測試的場景越來越多,測試數據越來越復雜的情況下,需要編寫更多的測心率函數,而這些函數的邏輯基本上是重復的。
?
在 pytest 當中可以使用參數化這種測試手段,簡化編寫用例函數的過程。我們并不需要為每一組測試數據單獨去編寫一個測試函數,而是采取多種數據共用一個函數的方式。如果測試操作幾乎一致,可以重復使用這一個函數進行測試。
import pytestcases = [(1, 2, 3),("hello", "world", "hello world"),(1, "world", "1world")]@pytest.mark.parametrize("a,b,expected", cases)def test_add(a, b, expected):assert expected == add(a, b)
在這個例子當中,cases 這個變量存儲了三組測試用例的數據,每一組測試數據用一個元組表示,元組的第 1 個元素代表 a,第 2 個元素代表 B,第 3 個元素代表預期結果。
@pytest.mark.parametrize("a,b,expected", cases) 這一行代碼的意思是說,每一次從 cases 變量當中取出一組測試數據。分別用 a、b 、expected 三個變量接收,然后我們把這三個變量名作為函數的參數傳遞到 test_add 當中,就實現了參數化的過程。
當使用這一種參數化的手段進行測試的時候,測試數據和測試函數是多對一的關系,對于多組測試數據,我們只需要去編寫一個測試函數,極大的提升了代碼編寫效率。
6、測試報告和插件
最后我們來說一下測試報告。pytest 當中的測試報告,通常是以插件的形式生成的,如果你想生成一個 HTML 格式的測試報告,可以先安裝 pytest-html 這個插件。
pip install pytest-html
接下來你需要在運行用例的時候,在 pytest 命令后面加上 --html=<測試報告名稱>.html
pytest --html=report.html
當運行完用例以后,你可以在當前目錄下找到一個 report.html 的文件,打開就可以查看測試報告了。
pytest 之所以成為主流,有很多的原因,其中最重要的一個原因是因為其強大的插件系統。任何一個程序員,只要遵循一些簡單的規范,就可以輕易的編寫插件。后面我們再跟大家深入去研究 pytest 當中的夾具系統,插件系統和鉤子函數這些特性。?
最后感謝每一個認真閱讀我文章的人,看著粉絲一路的上漲和關注,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走!?希望能幫助到你!【100%無套路免費領取】