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

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

unittest

認(rèn)識unittest

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

用例編寫

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

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發(fā)生改變不等于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如何編寫測試用例
導(dǎo)入unittest包

import unittest

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

class PrintTest(unittest.TestCase)

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

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

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

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

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

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

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

@classmethod
setUpClass()
    self.num=0

這樣表示在當(dāng)前類里所有測試用例執(zhí)行之前將self.num賦值為0,在用例執(zhí)行過程中不再執(zhí)行,適用于初始化測試環(huán)境

@classmethod
tearDownClass()
    self.num=0

這樣表示在當(dāng)前類里所有測試用例執(zhí)行完之后將self.num恢復(fù)為0,在單個用例執(zhí)行結(jié)束后不再執(zhí)行,適用于恢復(fù)測試環(huán)境,這里我強(qiáng)調(diào)一下這兩個類作用域僅限于當(dāng)前類里的所有test,不是所有的測試用例py文件
用例執(zhí)行

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

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

num0:3
num1:6
num3:0

num0:3
num2:3
num3:0

Ran 2 tests in 0.000s
OK

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

unittest小結(jié)

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

pytest

更完善的pytest

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

pytest用例編寫

我們首先說一下pytest的用例編寫規(guī)則:
測試文件以test_開頭(以test結(jié)尾也可以)
測試類以Test開頭,并且不能帶有 init 方法
測試函數(shù)以test
開頭
斷言還是繼承python的斷言assert
現(xiàn)在我們參照這個規(guī)則把上面的unittest框架的測試用例用pytest實現(xiàn)
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發(fā)生改變不等于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放在類名后面都不行,會加載不到里面的測試用例
測試環(huán)境數(shù)據(jù)初始化與恢復(fù)
pytest里面依然是使用setup()和teardown()作為初始化數(shù)據(jù)和恢復(fù)測試環(huán)境的方法,只不過是全小寫了而已。當(dāng)然在pytest也存在setup_class()和
teardown_class()這樣的類,用來在當(dāng)前測試類里所有測試用例執(zhí)行之前初始化和全部執(zhí)行完后恢復(fù)數(shù)據(jù)和環(huán)境,且不需要再使用@classmethod這樣的裝飾器進(jìn)行修飾
測試用例執(zhí)行
pytest在執(zhí)行測試用例時可以參數(shù)化,而且根據(jù)不同的需要可以定制化執(zhí)行結(jié)果,我們先簡單看幾個參數(shù):

    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的內(nèi)容打印出來,并輸出執(zhí)行結(jié)果和用時

    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的內(nèi)容了,他會展示每條case的執(zhí)行結(jié)果
當(dāng)然我們還可以組合使用

    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內(nèi)容還可以看到每條用例的執(zhí)行結(jié)果
常用命令參數(shù)

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

pytest小結(jié)

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

unittes VS pytest

用例編寫

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

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

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

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

1.測試文件必須以test開頭或者_(dá)test結(jié)尾

2.測試方法需以test開頭

3.測試類必須以Test開頭

前置跟后置

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

優(yōu)勢

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

斷言

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

2.pytest直接在assert 后面接表達(dá)式

失敗重跑

1.unittest無此功能

2.pytest支持

參數(shù)化

1.unittest需要依賴于ddt庫

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

擴(kuò)展性

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容