python測試框架 pytest


一:

pytest 是python的一套全功能的測試框架. 優點如下:

1、操作簡單,支持多組數據參數化, 支持用例的skip和xfail;

2、支持簡單的單元測試和復雜的功能測試,還可以做UI和接口自動化測試;

3、pytest有很多第三方的插件並且支持定義擴展; 如失敗重新執行, 斷言失敗也繼續運行,自定義出錯停止, 自定義mark標記靈活運行用例....

4、可以很好的集成CI

二:  

框架結構:

類似的setup,teardown同樣更靈活,

模塊級(setup_module/teardown_module)模塊始末,全局的

函數級(setup_function/teardown_function)不在類中的函數有用

類級(setup_class/teardown_class)只在類中前后運行一次。

方法級(setup_method/teardown_methond)運行在類中方法始末

session() 跨文件級

三:

Pytest調用方式和用例設計原則:

1. Pytest/py.test(終端,命令行,pycharm都行,可配置pycharm

使用pytest方式執行)

Pytest –v (最高級別信息—verbose -q靜默模式)

pytest -v -s -q 文件名 (s是帶控制台輸出結果,也是輸出詳細) 2. pytest將在當前目錄及其子目錄中運行test _ * .py或* _test.py形式

3. 以test_開頭的函數,以Test開頭的類,以test_開頭的方法。所有包package都要有__init__.py文件。

4. Pytest可以執行unittest框架寫的用例和方法

 

四:

Fixture: 對於setup和teardown  有些場景不適用, 同一個類里的用例  有的用例需要執行setup  有些用例不需要;這時候用fixture比較好用.

用法:

1、對於setup,teardown,可以不起這兩個名字,所以命名方式靈活。(可獨立命名,聲明后激活)

2、數據共享。在conftest.py配置里寫方法可以實現數據共享,不需要import導入。可以跨文件共享, 使用的文件與conftest文件在同一文件夾下;

3、 scope的層次及神奇的yield組合相當於各種setup 和 teardown的所有文件.

 

不想原測試方法有任何改動,或全部都自動實現自動應用,沒特例,也都不需要返回值時可以選擇自動應用

解決: 使用fixture中參數autouse=True實現

步驟:在方法上面加@pytest.fixture(autouse=True) 使用@pytest.mark.usefixtures

步驟:在測試方法上加@pytest.mark.usefixtures("start")

 

測試離不開數據,為了數據靈活,一般數據都是通過參數傳的

解決:fixture通過固定參數request傳遞;

步驟:在fixture中增加@pytest.fixture(params=[1, 2, 3, 'linda']) ; 在方法參數寫request

import pytest
#module模塊級,只在運行模塊式執行一次。如果不加范圍,默認會在該模塊中的每一個方法執行前執行;autouse=True設置后實現自動應用,后面模塊內所有的函數后面不用加方法名@pytest.fixture(scope="module", autouse=True)def open_browser():
    print("\n打開瀏覽器,打開網站首頁")
yield #模塊執行完case后 在最后執行一遍teardown操作。
print('執行teardown')
print('最后關閉瀏覽器')

def test_soso(login): #login函數寫在 conftest文件中 @pytest.fixture() def login():
print('case1: 登際后執行搜索')

def test_cakan():
print('case2:不登陸直接操作')

def test_cart(login):
print('case3,登陸后進行購物')

或者使用裝飾器方法:不改變原有代碼的情況下增加新功能,靈活的讓某個方法經過裝飾后具備 setup teardown 或其它功能項
@pytest.fixture()
def open_browser():
 print("\n打開瀏覽器,打開網站首頁")
yield
print('執行teardown')
print('最后關閉瀏覽器')

@pytest.mark.usefixtures('open_browser')
def test_soso(): #
def test_soso(open_browser) 效果是一樣的 但是這樣會改變原代碼結構,其他地方有復用的話就可能會有問題
 print('case1: 登際后執行搜索')
五:
常用依賴庫:

Pip install pytest-sugar
pip install pytest-rerunfailures Pip install pytest-xdist
Pip install pytest-assume
Pip intall pytest-html

 
六:
參數化和數據驅動:
test_user_data = ["zhangsan", "lisi"]

@pytest.fixture()
def login_r(request):
user = request.param
print("\n打開首頁准備登陸,登陸用戶:%s" % user)
return user

@pytest.mark.parametrize('login_r',test_user_data,indirect=True)
def test_login_s(login_r):
print(login_r)

等同於:
@pytest.fixture(params=test_user_data)
def login_r(request):
user = request.param
print("\n打開首頁准備登陸,登陸用戶:%s" % user)
return user

def test_login_s(login_r):
print(login_r)

多組數據:
test_user_data1 = [{"user": "linda", "password": "888888"},
{"user": "servenruby", "password": "123456"},
{"user": "test01", "password": ""}]

test_user_data2 = [{"q": "中國平安", "count": 3, "page": 1},
{"q": "阿里巴巴", "count": 2, "page": 2},
{"q": "pdd", "count": 3, "page": 1}]

@pytest.fixture(scope="module")
def login_r(request):
# 這是接收傳入的參數,接收一個參數
user = request.param['user']
password = request.param['password']
print("\n用戶名:%s,密碼:%s" % (user, password))

@pytest.fixture(scope="module")
def query_param(request):
# 這是接收傳入的參數,接收一第二個參數
    q = request.param['q']
count = request.param['count']
page = request.param['page']
print("查詢的搜索詞:%s" % q)
return request.param

# 這是pytest的參數化數據驅動,indeirect=True 是把login_r當作函數去執行,不寫的話會當它是參數
# 從下往上執行
# 兩個數據進行組合測試有3*3個測試用例執行(test_user_data1的個數*test_user_data2的個數)
@pytest.mark.parametrize("query_param", test_user_data2, indirect=True)
@pytest.mark.parametrize("login_r", test_user_data1, indirect=True)
def test_login(login_r, query_param):
# 登陸用例
print(login_r)
print(query_param)

mark中的skip與xfail

  1. 調試時不想運行這個用例

  2. 標記無法在某些平台上運行的測試功能,

  3. 當前的外部資源不可用時跳過(如果測試數據是從數據庫中取到的,連接數據庫的功能如果返回結 果未成功就不執行跳過,因為執行也都報錯)

  4. 在某些版本中執行,其他版本中跳過。

解決:@pytest.mark.skip跳過這個測試用例,可以加條件skipif,在滿足某些條件下才希望通過,否則跳過這個測試。

  1. 功能測試尚未實施或尚未修復的錯誤,當測試通過時盡管預計會失敗(標記為pytest.mark.xfail), 它是一個xpass,將在測試摘要中報告。

  2. 你希望測試由於某種情況而就應該失敗

解決:@pytest.mark.xfail



場景:只執行符合要求的某一部分用例 可以把一個web項目划分多個模塊,然后指定模塊名稱執行。

App自動化時,如果想Android和IOS公用一套代碼時,也可以使用標記功能,標明哪些是IOS 的用例,哪些是Android的,運行代碼時指定mark名稱運行就可以。

解決:

在測試用例方法上加@pytest.mark.webtest 執行:

-s參數: 輸出所有測試用的print信息 -m:執行自定義標記的相關用例

pytest -s test_mark_zi_09.py
pytest -s test_mark_zi_09.py -m=webtest #只執行標記為webtest的用例

pytest -s test_mark_zi_09.py -m apptest

pytest -s test_mark_zi_09.py -m "not ios" #不執行標記為 ios的用例




只執行符合要求的某一部分用例,通過類與方法的命名實現。通常編寫測試方法時
方法一:直接輸入文件名,類名 

pytest test_class_01.py
pytest -v -s test_class_01.py
pytest -v test_class_01.py::TestClass

pytest -v test_class_01.py::TestClass::test_one #只執行該測試類中的test_one

方法二 :使用-k

pytest -k "TestClass and test_one"  #只執行該測試類中的test_one

pytest -k "TestClass or test_one"

TestClass是類名,and是運算符,還可以是and not...,test_one是方法名中含有的信息。


正常全部執行完成后才能停止,如果想遇到錯誤時停止測試:- x;也可以當用例錯誤個數n達到指定數量時,停止測試:- - maxfail=n

pytest -x -v -s test_class_01.py
pytest -x -v -s test_class_01.py - -maxfail=2  #錯誤數達到2個時停止測試


十一

測試失敗后要重新運行n次,要在重新運行之間添加延遲時間, 間隔n秒再運行。

執行:
安裝:pip install pytest-rerunfailures

pytest --reruns 3 -v -s test_reruns_10.py pytest -v - -reruns 5 --reruns-delay 1


十二
一個方法中寫多條斷言,通常第一條過去,下面就不執行了。我們想報錯也都執行一下。

執行:安裝pip3 install pytest-assume

pytest.assume(1==4) #注意此處用的不是assert 斷言

pytest.assume(2==4)



十三

測試用例1000條,一個用例執行1鍾,一個測試人員執行需要1000分 鍾。通常我們會用人力成本換取時間成本,加幾個人一起執行,時間就會 縮短。如果10人一起執行只需要100分鍾,這就是一種並行測試,分布式場景。

解決:pytest分布式執行插件:pytest-xdist,多個CPU或主機執行 前提:用例之間都是獨立的,沒有先后順序,隨機都能執行,可重復運行

不影響其他用例。
安裝:Pip3 install pytest-xdist

多個CPU並行執行用例,直接加-n 3是並行數量:pytest -n 3 在多個終端下一起執行

 
            

Pytest -v -s --html=report.html  #生成html報告  利用 pytest-html









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM