自動化測試入門(unittest和pytest)

在我們真正的編寫測試用例之前,我們需要了解一下測試框架。目前python自帶的unittest和第三方測試框架pytest這兩個測試框架比較流行,unittest在過去使用的人很多,近兩年pytest有逐漸取代unittest之勢。今天我們先了解一下這兩個測試框架。

unittest

認識unittest

在我們真正的編寫測試用例之前,我們需要了解一下測試框架。
unittest是python自帶的單元測試框架,盡管其主要是為單元測試服務的,但我們也可以用它來做自動化測試。
unittest框架為我們編寫用例提供了如下的能力:
定義用例的能力。unittest框架有一套固有套路,可以讓我們定義測試用例時更加簡單和統一
斷言的能力。unittest框架提供了一系列的斷言
各種執行策略。通過test suit或者擴展的方式,我們可以自定義用例執行的策略

用例編寫

我們先說一下用例的格式吧,我們先寫個測試用例吧:

import unittest
class PrintTest(unittest.TestCase):
    def setUp(self):
        self.num = 3
        print("num0:%s"%self.num)

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        self.assertEqual(self.num,6,"self.num發生改變不等于3")

    def test_test2(self):
        print("num2:%s"%self.num)

    def tearDown(self):
        self.num = 0
        print("num3:%s"%self.num)
        
        
if __name__ == '__main__':
    unittest.main()

接下來由這個例子給大家講一下unittest如何編寫測試用例
導入unittest包

import unittest

這個就不用我多說了吧,python語言需要用哪個包或者模塊時候一定要先導入才能使用
定義測試類

class PrintTest(unittest.TestCase)

初學者看到這一行就害怕,其實大可不必。暫且把它當作是一個套路吧,測試類的名字你可以隨意取,當然了最好遵循python的PEP8規范,這樣代碼看起來更加整潔美觀。所有的測試類都必須直接或間接的繼承自unittest.TestCase類。總之,這還是套路,記住就好。
用例初始化數據

    def setUp(self):
        self.num = 3
        print("num0:%s"%self.num)

setUp(self)方法是一個測試用例初始化方法,在每個測試用例執行之前都會執行一次,是做數據初始化的好地方。在上面的例子里,我們為每一個測試方法都定義了被測對象--self.num,通俗一點就是每次執行測試用例時,self.num都會被賦值為3
測試用例

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        self.assertEqual(self.num,3,"self.num發生改變不等于3")

首先,在unittest測試框中,他會把以test開頭的函數做位測試用例,換句話說,就是每個測試用例的命名已經做了約束,開頭必須是test,只有test開頭的才是測試用例
另外,unittest框架自身也有斷言,斷言是測試用例的一個重要組成部分,斷言的設置直接決定著自動化測試用例的效果。這里強調一下,大家一定要養成在斷言后加入自己業務相關的信息,方便根據自動化報告分析錯誤,可以提高發現問題的效率
測試環境恢復

    def tearDown(self):
       self.num = 0
       print("num3:%s"%self.num)

在測試過程中,是需要對測試后的環境和數據進行恢復的,在unittest測試框架中,tearDown(self)這個方法就是用來恢復測試環境的,每個用例執行完都會執行一遍
這里我在補充一點,如果是測試環境需要初始化和恢復,而且不需要每個測試用例都初始化,我們可以用setUpClass()和tearDownClass()這兩個類,但是必須使用@classmethod裝飾器進行修飾

@classmethod
setUpClass()
    self.num=0

這樣表示在當前類里所有測試用例執行之前將self.num賦值為0,在用例執行過程中不再執行,適用于初始化測試環境

@classmethod
tearDownClass()
    self.num=0

這樣表示在當前類里所有測試用例執行完之后將self.num恢復為0,在單個用例執行結束后不再執行,適用于恢復測試環境,這里我強調一下這兩個類作用域僅限于當前類里的所有test,不是所有的測試用例py文件
用例執行

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

依然是套路,上面的代碼表示,如果直接執行該python文件的話,就運行所有的測試類里的測試用例,也就是運行所有的以test開頭的方法,我們姑且這么認為,unittest.main()是最簡單的用例執行方法
接下來我們將上述代碼運行一遍看看結果

num0:3
num1:6
num3:0

num0:3
num2:3
num3:0

Ran 2 tests in 0.000s
OK

從結果我們可以看到,每個測試用例執行順序是setUp-->test_case-->tearDown

unittest小結

使用unittest的話需要記住下面的幾點
導入unittest
定義繼承自unittest.TestCase的測試類
定義以test開頭的測試方法,這個方法就是測試用例,你可以在一個類里定義n個測試用例
斷言后面的信息盡量和自己業務相關,方便定位問題
unittest.main()是執行測試用例最簡單的方式

pytest

更完善的pytest

近兩年pytest使用的人也越來越多,主要是pytest的擴展性和其他方面的功能要比unittest更完善,最最重要的是,pytest可以兼容unittest,也就是說unittest的測試用例在pytest框架里也能執行,但是要注意的一點是文件名要符合pytest的規則。

pytest用例編寫

我們首先說一下pytest的用例編寫規則:
測試文件以test_開頭(以test結尾也可以)
測試類以Test開頭,并且不能帶有 init 方法
測試函數以test
開頭
斷言還是繼承python的斷言assert
現在我們參照這個規則把上面的unittest框架的測試用例用pytest實現
test_print.py

import pytest
class TestPrint:
    def setup(self):
        self.num = 3
        print("num0:%s"%self.num)

    def test_test1(self):
        self.num= self.num+3
        print("num1:%s"%(self.num))
        assert self.num==6,"self.num發生改變不等于6"

    def test_test2(self):
        print("num2:%s"%self.num)

    def teardown(self):
        self.num = 0
        print("num3:%s"%self.num)


if __name__ == '__main__':
    pytest.main(['-s', 'test_print.py'])

定義測試類

class TestPrint:

測試類一定要以Test開頭,記住,還是套路,小寫test或者Test放在類名后面都不行,會加載不到里面的測試用例
測試環境數據初始化與恢復
pytest里面依然是使用setup()和teardown()作為初始化數據和恢復測試環境的方法,只不過是全小寫了而已。當然在pytest也存在setup_class()和
teardown_class()這樣的類,用來在當前測試類里所有測試用例執行之前初始化和全部執行完后恢復數據和環境,且不需要再使用@classmethod這樣的裝飾器進行修飾
測試用例執行
pytest在執行測試用例時可以參數化,而且根據不同的需要可以定制化執行結果,我們先簡單看幾個參數:

    pytest.main(['-s', 'test_print.py'])

#output:
collected 2 items

test_print.py num0:3
num1:6
.num3:0
num0:3
num2:3
.num3:0
============================== 2 passed in 0.08s ==============================

可以把print的內容打印出來,并輸出執行結果和用時

    pytest.main(['-v', 'test_print.py'])

#output:
collecting ... collected 2 items

test_print.py::TestPrint::test_test1 PASSED                              [ 50%]
test_print.py::TestPrint::test_test2 PASSED                              [100%]

============================== 2 passed in 0.09s ==============================

這里是不是沒有print的內容了,他會展示每條case的執行結果
當然我們還可以組合使用

    pytest.main(['-v','-s', 'test_print.py'])

#output:
collecting ... collected 2 items
test_print.py::TestPrint::test_test1 num0:3
num1:6
PASSEDnum3:0
test_print.py::TestPrint::test_test2 num0:3
num2:3
PASSEDnum3:0
============================== 2 passed in 0.06s ==============================

既可以顯示print內容還可以看到每條用例的執行結果
常用命令參數

命令行 解釋
pytest --version 顯示版本信息
pytest --fixtures 顯示可用的內置函數
pytest -h --help 顯示參數和配置的幫助信息
pytest --lf 運行上一次運行失敗的用例
pytest -x --exitfirst 第一次失敗后停止
pytest --maxfail=2 第二(n)次失敗后停止
pytest test_mod.py 運行單個文件中的用例
pytest testcase/ 運行文件夾下的用例
pytest -k "MyClass and not method" 關鍵字表達式(文件名、類名、方法名)運行測試用例
(將運行TestMyClass.test_something 不運行TestMyClass.test_method_simple)
pytest test_mod.py::test_func 運行模塊內特指的方法
pytest test_mod.py::TestClass::test_method 運行模塊下類內特指的方法
pytest -m slow marker運行測試用例(運行所有被裝飾器標記@pytest.mark.slow的用例)
pytest --pyargs pkg.testing 從包中運行測試用例(這將要導入import pkg.testing)
pytest -ra 運行測試用例(顯示測試總的結果信息,輸出信息的最后)
pytest -rp 運行測試用例(顯E示測試通過的結果信息,輸出信息的最后)
pytest -rE 運行測試用例(顯示測試錯誤的結果信息,輸出信息的最后)
pytest -rs 運行測試用例(顯示測試跳過的結果信息,輸出信息的最后),也可以結合使用 -rfs – 顯示跳過、失敗的
pytest -v pytest1.py 用于顯示每個測試函數的執行結果
pytest -q pytest1.py 只顯示整體測試結果
pytest -s pytest1.py 用于顯示測試函數中print()函數輸出
pytest --durations=10 獲得最慢的10個測試持續時間表
pytest --junitxml=path 生成一個結果集xml文件,可用于Jenkins 持續集成
pytest --pastebin=failed 為每個失敗的用例創建一個URL

pytest小結

關于pytest的使用方法我就先介紹這么多了,關于pytest的其他更高階的用法,大家可以去查閱pytest使用手冊

unittes VS pytest

用例編寫

使用unittest編寫測試用例必須遵循以下規則:

1.測試類必須要繼承 unittest.TestCase

2.測試方法必須以test_kai開頭

pyest是Python的第三方測試框架,是基于unittest的擴展框架,比unittest更簡潔高效,使用pytest編寫測試用例必須遵循以下規則:

1.測試文件必須以test開頭或者_test結尾

2.測試方法需以test開頭

3.測試類必須以Test開頭

前置跟后置

1.unittest提供了setUp/tearDown,每個用例運行前、結束后運行一次。setUpClass和tearDownClass,用例執行前、結束后,只運行一次。
2.pyets 可以在函數前使用@pytest.fixture()裝飾器,fixture使用范圍可以是:function(函數級別)、class、module(模塊級別)、package(包級別)、session(多個測試類可以共用一個session)

優勢

1.fixure命名更加靈活,局限性比較小
2.conftest.py 配置里可以實現數據共享,不需要import就能自動找到一些配置,可供多個py文件調用。
3.scope="session" 以實現多個.py跨文件使用一個session來完成多個用例

斷言

1.unittest提供了assertEqual、assertIn、assertTrue、assertFalse等

2.pytest直接在assert 后面接表達式

失敗重跑

1.unittest無此功能

2.pytest支持

參數化

1.unittest需要依賴于ddt庫

2.pytest直接使用@pytest.mark.parametrize裝飾器

擴展性

與unittest相比,pytest具有很多第三方插件,并且可以自定義擴展,比較好用的如pytest-selenium(集成selenium)、pytest-html(完美html測試報告生成)、pytest-xdist(多CPU分發)等

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容