【轉】pytest+allure詳細版


 轉載自:https://blog.csdn.net/qq_42610167/article/details/101204066

感謝博主:天蠍座的測試之旅

文章目錄

一:pytest的介紹,安裝,框架結構,執行方式

1,特點

:1. 簡單靈活,容易上手;支持參數化; 測試用例的skip和xfail 處理;
2. 能夠支持簡單的單元測試和復雜的功能測試,還可以用來做 selenium/appium等自動化測試、接口自動化測試 (pytest+requests);
3. pytest具有很多第三方插件,並且可以自定義擴展, 比較好 用的如 pytest-allure(完美html測試報告生成) pytest-xdist (多CPU分發)等;
4. 可以很好的和jenkins集成;**

2,安裝

pytest安裝,導入相關依賴庫
Pip install –U pytest U表示升級
Pip install sugar
pip install pytest-rerunfailures
Pip install pytest-xdist
Pip install pytest-assume
Pip intall pytest-html …
Pip list查看
Pytest –h 幫助**

3, pytest的框架結構

Import pytest 類似的setup,teardown同樣更靈活
模塊級 (setup_module/teardown_module)
        全局的,整個.py模塊開始前和結束后調用一次
函數級 (setup_function/teardown_function) 

  只對函數用例生效(不在類內),每個函數級用例開始和結束時調用一次
類級 (setup_class/teardown_class)
  只在前后運行一次(在類中)。
方法級 (setup_method/teardown_methond)
   運行在類中方法始末

類里面的(setup/teardown):運行在調用方法的前后

類中運行順序:setup_class>setup_method>setup>用例>teardown>teardown_method>teardown_class

4,執行方式

Pytest/py.test(終端,命令行,pycharm可配置pytest方式執行)

  1. Pytest –v (最高級別信息—verbose)
  2. pytest -v -s filename 3.Pytest-q (靜默)
    (輸出打印)
    多種執行方式
    1.pytest將在當前目錄及其子目錄中運行test _ * .py或* test.py形 式的所有文件。
    2.以test_開頭的函數,以Test開頭的類,以test_開頭的方法。所有包 package都要有__init
    _.py文件。
    3.Pytest可以執行unittest框架寫的用例和方法
  3. 可以在pytest.ini文件中自定義要運行的測試路徑、文件名、類名和方法名等。

二:Pytest -斷言、跳過及運行

1,Pytest -斷言、跳過及運行

在這里插入圖片描述
在這里插入圖片描述

2,mark中的skip(跳過)

在這里插入圖片描述

3,mark中的xfail(失敗)

在這里插入圖片描述])

  skip和xfail的用法詳細參考:https://www.cnblogs.com/crystal1126/p/12221168.html

 

4,使用自定義標記mark只執行部分用例

在這里插入圖片描述
1.mark標記
以下用例,標記test_send_http()為webtest

# content of test_server.py

import pytest

@pytest.mark.webtest
def test_send_http():
    pass # perform some webtest test for your app

def test_something_quick():
    pass

def test_another():
    pass

class TestClass:
    def test_method(self):
        pass

if __name__ == "__main__":
    pytest.main(["-s", "test_server.py", "-m=webtest"])
只運行用webtest標記的測試,cmd運行的時候,加個-m 參數,指定參數值webtest

```py
pytest -v -m webtest
 

如果不想執行標記webtest的用例,那就用”not webtest”

pytest -v -m “not webtest”
import pytest

@pytest.mark.webtest
def test_send_http():
    pass # perform some webtest test for your app
def test_something_quick():
    pass
def test_another():
    pass
class TestClass:
    def test_method(self):
        pass

if __name__ == "__main__":
    pytest.main(["-s", "test_server.py", "-m='not webtest'"])

5,文件名::類名::方法執行部分用例

在這里插入圖片描述
2.-v 指定的函數節點id
如果想指定運行某個.py模塊下,類里面的一個用例,如:TestClass里面testmethod用例
每個test開頭(或_test結尾)的用例,函數(或方法)的名稱就是用例的節點id,指定節點id運行用-v 參數

pytest -v test_server.py::TestClass::test_method

當然也能選擇運行整個class

 pytest -v test_server.py::TestClass

也能選擇多個節點運行,多個節點中間空格隔開

pytest -v test_server.py::TestClass test_server.py::test_send_http

6,-k 組合調用執行部分用例

在這里插入圖片描述
.-k 匹配用例名稱
可以使用-k命令行選項指定在匹配用例名稱的表達式

pytest -v -k http

您也可以運行所有的測試,根據用例名稱排除掉某些用例:

pytest -k “not send_http” -v

也可以同時選擇匹配 “http” 和“quick”

pytest -k “http or quick” -v

三, Pytest -fixture

pytest 相較於 unittest 最為跳躍的一點應該就是 fixture 機制

對於unittest來說,每個用例的類中都需要去寫入setUp和tearDown。也就是我們所說的前置和后置,

而不可避免的,很多用例的前置和后置都是一樣(例如很多用例都需要前置登錄,后置退出),於是我們需要重復的復制粘貼,這樣導致工作量增加,代碼量也增加,界面也顯得冗雜。

所以此時pytest中fixture機制便要閃亮登場了

通俗的講: fixture = 前置+后置

而方便的是:如果很多用例都有同樣的前置和后置,那么我就只實現一個,然后需要的用例就去調用就好了。

1.機制:與測試用例同級,或者是測試用例的父級,創建一個conftest.py文件。
2.conftest.py文件里:放所有的前置和后置。 不需要用例.py文件主動引入conftest文件。
3.定義一個函數:包含前置操作+后置操作。
4.把函數聲明為fixture :在函數前面加上 @pytest.fixture(作用級別=默認為function)
5.fixture的定義。
  如果有返回值,那么寫在yield后面。(yield的作用就相當於return)
  在測試用例當中,調用有返回值的fixture函數時,函數名稱就是代表返回值。
  在測試用例當中,函數名稱作為用例的參數即可。

1. 如下: 定義一個函數名叫open_url的fixture前后置,前置為打開鏈接,后置為退出瀏覽器

@pytest.fixture(scope=“class”) #定義scope的范圍

  def open_url():
    # 前置
    driver = webdriver.Chrome()
    driver.get(url) #url為鏈接地址
    yield driver    #yield之前代碼是前置,之后的代碼就是后置。
    # 后置
    driver.quit()

這樣我們就定義了一個叫做 open_url 的 fixture

2.在我們要用這個前后置的類前面 我們用@pytest.mark.usefixtures(fixture函數名)

就可以直接調用上面定義好的這個前后置
在這里插入圖片描述
可以看到 在TestLogin 這個類中 我們不再去編寫setup 和 teardown. 直接寫我們的中間過程就可以了。是不是很方便了?

3.進階方法:conftest中定義多個fixture,一個fixture可以是另一個fixture的前后置,期間還是用yield隔開前后置

如上圖中可以看到我class中另外還引用了一個名為refresh_page的fixture,直接上代碼:

# 刷新頁面 - 定義的第二個fixture
@pytest.fixture
def refresh_page(open_url):
    yield
    open_url.refresh()

直接將open_url作為了另一個fixture的前置引用進來,用yield隔開,當用例中執行完open_url前后置后,再執行了一次refresh的后置。
執行順序: open_url yield 之前代碼 – 用例代碼 – open_url yield 之后代碼 --》 refresh_page yield 之后代碼
是不是很妙,可以解決許多用例流程環環相扣時的麻煩。

4.說到上面的多個fixture調用,很多人就會疑惑,會不會fixture之間相互沖突。

當然是不會了,fixture在conftest.py當中就已經決定了他的用例域,他會主動去區分你這個fixture是作用在哪個用例域。
首先我們看一下框架中對於fixture函數的定義: 在這里插入圖片描述

scope:定義用例域的范圍:
function:默認范圍,每一個函數或方法都會調用,不填寫時便是它
class:每一個類調用一次
module: 每一個.py文件調用一次,文件中可以有多個function和class
session:多個文件調用一次,可以跨文件,如在.py文件中,每一個.py文件就是module
范圍:
session > module > class > function

所以在調用時各個fixture之間並不會相互沖突。

5,fixture的自動應用autouse

autouse調用例子:**
當管理用例比較多的時候,這種方法比較方便高效,但是用該功能時也要小心,一定要注意fixture的作用范圍。需要注意的是,當使用這種方式時,就不能使用返回值的功了。autouse默認設置為False。當默認為False,就可以選擇用上面兩種方式來試用fixture。當設置為True時,所有的test都會自動調用這個fixture。autouse遵循scope="關鍵字參數"規則:當scope="session"時,無論怎樣定義只運行一次;當scope="module"時,每個py文件只運行一次;當scope="class"時,每個class只運行一次(但是一個文件中包括function和class時,會在每個function(不在class中)運行一次);當scope="function"時,每個function運行一次;
‘’’
平常寫自動化用例會寫一些前置的fixture操作,用例需要用到就直接傳該函數的參數名稱就行了。當用例很多的時候,每次都傳這個參數,會比較麻煩。
fixture里面有個參數autouse,默認是Fasle沒開啟的,可以設置為True開啟自動使用fixture功能,這樣用例就不用每次都去傳參了

設置autouse=True
autouse設置為True,自動調用fixture功能
start設置scope為module級別,在當前.py用例模塊只執行一次,autouse=True自動使用[圖片]open_home設置scope為function級別,
每個用例前都調用一次,自動使用

import pytest

@pytest.fixture(scope="module",autouse=True)
def start(request):
    print("\n----開始執行module------")
    print('module : %s'% request.module.__name__)
    print('------啟動瀏覽器-------')
    yield
    print("------結束測試 end!----------")

@pytest.fixture(scope="function",autouse=True)
def open_home(request):
    print("function:%s \n--回到首頁--"% request.function.__name__)

def test_01():
    print('----用例01-----')

def test_02():
    print('----用例02-----')

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

執行結果

----開始執行module------
module : autouse
------啟動瀏覽器-------
function:test_01 
--回到首頁--
.----用例01-----
function:test_02 
--回到首頁--
.----用例02-----
------結束測試 end!----------

四,參數化與數據驅動框架實現

參數化1

import pytest
@pytest.fixture(params=[1, 2, 3])
def need_data(request):  # 傳入參數request 系統封裝參數
    return request.param  # 取列表中單個值,默認的取值方式

class Test_ABC:
    def test_a(self, need_data):
        print("------->test_a")
        assert need_data != 3  # 斷言need_data不等於3

 

參數化2

1、直接傳入測試數據

import pytest
class Test_ABC:
    def setup_class(self):
        print("------->setup_class")

    def teardown_class(self):
        print("------->teardown_class")

    @pytest.mark.parametrize("a,b",[(1,2),(0,3)]) #直接傳入數據
    def test_a(self, a, b):
        print("test data:a=%d,b=%d" % (a, b))
        assert a + b == 3

2、使用函數返回值傳入數據

import pytest


def return_test_data():
    return [(1, 2), (0, 3)]

class Test_ABC:
    def setup_class(self):
        print("------->setup_class")

    def teardown_class(self):
        print("------->teardown_class")

    @pytest.mark.parametrize("a,b", return_test_data())  # 使用函數返回值的形式傳入參數值
    def test_a(self, a, b):
        print("test data:a=%d,b=%d" % (a, b))
        assert a + b == 3

結果與1中的結果一致。

參數化3

 

案例一
import pytest test_user_data=['linda','sai','tom'] @pytest.fixture(scope='module') def login(request): user=request.param print('打開首頁登陸%s'%user) return user #indirect=True是把login當作函數去執行 @pytest.mark.parametrize('login',test_user_data,indirect=True) def test_cart(login): usera=login print('不同用戶添加購物車%s'%usera) assert usera!='' Process finished with exit code 0 打開首頁登陸linda PASSED [ 33%]不同用戶添加購物車linda 打開首頁登陸sai PASSED [ 66%]不同用戶添加購物車sai 打開首頁登陸tom PASSED [100%]不同用戶添加購物車tom

 
案例二
import pytest test_user_data=[ {'user':'linda','password':'8888'}, {'user':'servenruby','password':'123456'}, {'user':'test01','password':''} ] @pytest.fixture(scope='module') def login_r(request): #可以通過dict形式,雖然傳遞一個參數,但通過key的方式可以達到累死傳入多個參數的效果 user=request.param['user'] pwd=request.param['password'] print('\n打開首頁准備登陸,登陸用戶%s,密碼%s'%(user,pwd)) if pwd: return True else: return False #這是pytest參數化驅動,indeirect=True是把login_r當作函數去執行 @pytest.mark.parametrize('login_r',test_user_data,indirect=True) def test_cart(login_r): #登陸用例 a=login_r print('測試用例中login_r的返回值%s'%a) assert a,'失敗原因,密碼為空' 開首頁准備登陸,登陸用戶linda,密碼8888 PASSED [ 33%]測試用例中login_r的返回值True 打開首頁准備登陸,登陸用戶servenruby,密碼123456 PASSED [ 66%]測試用例中login_r的返回值True 打開首頁准備登陸,登陸用戶test01,密碼 FAILED [100%]測試用例中login_r的返回值False 打開首頁准備登陸,登陸用戶linda,密碼8888 PASSED [ 33%]測試用例中login_r的返回值True 打開首頁准備登陸,登陸用戶servenruby,密碼123456 PASSED [ 66%]測試用例中login_r的返回值True 打開首頁准備登陸,登陸用戶test01,密碼 FAILED [100%]測試用例中login_r的返回值False test_mark_param_request2.py:19 (test_cart[login_r2]) login_r = False @pytest.mark.parametrize('login_r',test_user_data,indirect=True) def test_cart(login_r): #登陸用例 a=login_r print('測試用例中login_r的返回值%s'%a) > assert a,'失敗原因,密碼為空' E AssertionError: 失敗原因,密碼為空 E assert False

參數化3*3

import pytest
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']
    pwd=request.param['password']
    print('\n用戶名:%s,密碼:%s'%(user,pwd))

@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)


pytest_mark_request3.py::test_login[login_r1-query_param0]44% ████▌ 查詢的搜索詞pdd
None
{'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r1-query_param2]56% █████▋
用戶名:linda,密碼:888888
None
{'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r0-query_param2]67% ██████▋
用戶名:test01,密碼:
None
{'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r2-query_param2]78% ███████▊ 查詢的搜索詞阿里巴巴
None
{'q': '阿里巴巴', 'count': 2, 'page': 2}

pytest_mark_request3.py::test_login[login_r2-query_param1]89% ████████▉ 查詢的搜索詞中國平安
None
{'q': '中國平安', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r2-query_param0]100% ██████████

五,第三方插件

1,調整測試用例的執行順序

在這里插入圖片描述
場景:未考慮按自然順序執行時,或想變更執行順序,比如增加 數據的用例要先執行,再執行刪除的用例。測試用例默認是按名 稱順序執行的。
• 解決:
• 安裝:pip install pytest-ordering
• 在測試方法上加下面裝飾器
•@pytest.mark.last    —最后一個執行
• @pytest.mark.run(order=1)—第幾個執行
pytest默認按字母順序去執行的

import pytest
@pytest.mark.run(order=1)
def test_01():
    print('test01')

@pytest.mark.run(order=2)
def test_02():
    print('test01')
@pytest.mark.last
def test_06():
    print('test01')

def test_04():
    print('test01')

def test_05():
    print('test01')
@pytest.mark.run(order=3)
def test_03():
    print('test01')

pytest_order.py::test_01 PASSED [ 16%]test01

pytest_order.py::test_02 PASSED [ 33%]test01

pytest_order.py::test_03 PASSED [ 50%]test01

pytest_order.py::test_04 PASSED [ 66%]test01

pytest_order.py::test_05 PASSED [ 83%]test01

pytest_order.py::test_06 PASSED [100%]test01

2, 執行用例遇到錯誤停止

在這里插入圖片描述
• 正常全部執行完成后才能停止,如果想遇到錯誤時停止測試: -x;也可以當用例錯誤個數n達到指定數量時,停止測試:- - maxfail=n
• 執行:
• pytest -x -v -s 文件名.py      ------- -x是遇到錯誤就停止
• pytest -x -v -s 文件名.py —maxfail=2  ------- --maxfail=2 是遇到兩個錯誤就停止

3,執行用例失敗后重新運行

在這里插入圖片描述
**場景:
• 測試失敗后要重新運行n次,要在重新運行之間添加延遲時 間,間隔n秒再運行。
• 執行:
• 安裝:pip install pytest-rerunfailures
• pytest -v - -reruns 5 --reruns-delay 1 —每次等1秒 重試5次

4,多條斷言前面報錯后面依然執行

在這里插入圖片描述
pip3 install pytest-assume 斷言后繼續執行,但要修改斷言**

@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_assume(x, y):
    pytest.assume(x == y)
    pytest.assume(3 == 4)
    pytest.assume(5 == 9)

5,多線程並行與分布式執行

在這里插入圖片描述
場景:測試用例1000條,一個用例執行1鍾,一個測試人員執行需要1000分 鍾。通常我們會用人力成本換取時間成本,加幾個人一起執行,時間就會縮
短。如果10人一起執行只需要100分鍾,這就是一種並行測試,分布式場景。
解決:pytest分布式執行插件:pytest-xdist,多個CPU或主機執行
前提:用例之間都是獨立的,沒有先后順序,隨機都能執行,可重復運行不 影響其他用例。
安裝:Pip3 install pytest-xdist
• 多個CPU並行執行用例,直接加-n 3是並行數量:pytest -n 3 • 在多個終端下一起執行

import pytest
import time

@pytest.mark.parametrize('x',list(range(10)))
def test_somethins(x):
    time.sleep(1)

pytest -v -s -n 5 test_xsdist.py  ----一次執行5

運行以下代碼,項目結構如下

web_conf_py是項目工程名稱

│  conftest.py
│  __init__.py
│              
├─baidu
│  │  conftest.py
│  │  test_1_baidu.py
│  │  test_2.py
│  │  __init__.py 
│          
├─blog
│  │  conftest.py
│  │  test_2_blog.py
│  │  __init__.py
 

代碼參考:

# web_conf_py/conftest.py
import pytest

@pytest.fixture(scope="session")
def start():
    print("\n打開首頁")
    return "yoyo"

# web_conf_py/baidu/conftest.py
import pytest

@pytest.fixture(scope="session")
def open_baidu():
    print("打開百度頁面_session")

# web_conf_py/baidu/test_1_baidu.py
import pytest
import time

def test_01(start, open_baidu):
    print("測試用例test_01")
    time.sleep(1)
    assert start == "yoyo"

def test_02(start, open_baidu):
    print("測試用例test_02")
    time.sleep(1)
    assert start == "yoyo"

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


# web_conf_py/baidu/test_2.py
import pytest
import time

def test_06(start, open_baidu):
    print("測試用例test_01")
    time.sleep(1)
    assert start == "yoyo"
def test_07(start, open_baidu):
    print("測試用例test_02")
    time.sleep(1)
    assert start == "yoyo"

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


# web_conf_py/blog/conftest.py
import pytest

@pytest.fixture(scope="function")
def open_blog():
    print("打開blog頁面_function")

# web_conf_py/blog/test_2_blog.py

import pytest
import time
def test_03(start, open_blog):
    print("測試用例test_03")
    time.sleep(1)
    assert start == "yoyo"

def test_04(start, open_blog):
    print("測試用例test_04")
    time.sleep(1)
    assert start == "yoyo"

def test_05(start, open_blog):
    '''跨模塊調用baidu模塊下的conftest'''
    print("測試用例test_05,跨模塊調用baidu")
    time.sleep(1)
    assert start == "yoyo"

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

正常運行需要消耗時間:7.12 seconds

E:\YOYO\web_conf_py>pytest
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: E:\YOYO\web_conf_py, inifile:
plugins: xdist-1.23.2, metadata-1.7.0, html-1.19.0, forked-0.2
collected 7 items

baidu\test_1_baidu.py ..                                                 [ 28%]
baidu\test_2.py ..                                                       [ 57%]
blog\test_2_blog.py ...                                                  [100%]

========================== 7 passed in 7.12 seconds ===========================

設置並行運行數量為3,消耗時間:3.64 seconds,大大的縮短了用例時間

E:\YOYO\web_conf_py>pytest -n 3
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: E:\YOYO\web_conf_py, inifile:
plugins: xdist-1.23.2, metadata-1.7.0, html-1.19.0, forked-0.2
gw0 [7] / gw1 [7] / gw2 [7]
scheduling tests via LoadScheduling
.......                                                                  [100%]
========================== 7 passed in 3.64 seconds ===========================

6,其他有意思的插件

在這里插入圖片描述
這里就不多說了,喜歡的可以自己研究下

7,使用pytest執行unittest的測試用例

在這里插入圖片描述
執行unitest就和原來一樣,盡量不要混合使用搞那些花里胡哨的,用哪個就哪個,就不多說了

8,pytest-html生成報告

在這里插入圖片描述
pytest-HTML是一個插件,pytest用於生成測試結果的HTML報告。兼容Python 2.7,3.6

pytest-html
1.github上源碼地址【https://github.com/pytest-dev/pytest-html】

2.pip安裝

$ pip install pytest-html

在這里插入圖片描述

3.執行方法

$ pytest --html=report.html

html報告
1.打開cmd,cd到需要執行pytest用例的目錄,執行指令:pytest --html=report.html

image
2.執行完之后,在當前目錄會生成一個report.html的報告文件,顯示效果如下

image
指定報告路徑
1.直接執行"pytest --html=report.html"生成的報告會在當前腳本的同一路徑,如果想指定報告的存放位置,放到當前腳本的同一目錄下的report文件夾里

pytest --html=./report/report.html

在這里插入圖片描述
2.如果想指定執行某個.py文件用例或者某個文件夾里面的所有用例,需加個參數。具體規則參考【pytest文檔2-用例運行規則】

在這里插入圖片描述
報告獨立顯示
1.上面方法生成的報告,css是獨立的,分享報告的時候樣式會丟失,為了更好的分享發郵件展示報告,可以把css樣式合並到html里

$ pytest --html=report.html --self-contained-html

顯示選項
默認情況下,“ 結果”表中的所有行都將被展開,但具測試通過的行除外Passed。

可以使用查詢參數自定義此行為:?collapsed=Passed,XFailed,Skipped。

更多功能
1.更多功能查看官方文檔【https://github.com/pytest-dev/pytest-html】

六,日志管理及代碼覆蓋率

1, pytest中logging的應用

在這里插入圖片描述

2, 日志及級別的含義

在這里插入圖片描述
自動化測試用例的調試信息非常有用,可以讓我們知道現在的運行情況到,執行到哪步以及相應的出錯信息等,可以在pytest里面,有時並不會輸出所有信息,比如默認情況下pass的測試用例是沒有print輸出的。本文將介紹如何在pytest里面實時顯示所有的log信息。

1. 用print輸出log信息
slowTest_print.py

import time
 
def test_1():
    print 'test_1'
    time.sleep(1)
    print 'after 1 sec'
    time.sleep(1)
    print 'after 2 sec'
    time.sleep(1)
    print 'after 3 sec'
    assert 1, 'should pass'
 
def test_2():
    print 'in test_2'
    time.sleep(1)
    print 'after 1 sec'
    time.sleep(1)
    print 'after 2 sec'
    time.sleep(1)
    print 'after 3 sec'
    assert 0, 'failing for demo purposes'

運行上述程序,pytest會capture所有的輸出,保存直到所有的測試用例都執行結束,並且只輸出那些失敗的測試用例的信息,對於成功的測試用例,沒有print的信息顯示。
從下面的運行結果,如果需要查看test_1()的運行情況,沒有log信息可看,print沒有顯示。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v slowTest_print.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_print.py::test_1 PASSED
slowTest_print.py::test_2 FAILED

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        print 'in test_2'
        time.sleep(1)
        print 'after 1 sec'
        time.sleep(1)
        print 'after 2 sec'
        time.sleep(1)
        print 'after 3 sec'
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_print.py:22: AssertionError
---------------------------- Captured stdout call -----------------------------
in test_2
after 1 sec
after 2 sec
after 3 sec
===================== 1 failed, 1 passed in 6.45 seconds ======================

C:\Users\yatyang\PycharmProjects\pytest_example>

我們可以用‘-s’參數或者 ‘–capture=no’,這樣就可以輸出所有測試用的print信息。但是pytest還是會等着所有的測試用例都執行完畢才會顯示運行結果。可以看到下面的test_1也顯示出print的相關信息。


C:\Users\yatyang\PycharmProjects\pytest_example>py.test --capture=no slowTest_print.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_print.py test_1
after 1 sec
after 2 sec
after 3 sec
.in test_2
after 1 sec
after 2 sec
after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        print 'in test_2'
        time.sleep(1)
        print 'after 1 sec'
        time.sleep(1)
        print 'after 2 sec'
        time.sleep(1)
        print 'after 3 sec'
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_print.py:22: AssertionError
===================== 1 failed, 1 passed in 6.17 seconds ======================

2. Python Logging用法
一般情況下,一些程序的調試過程中我們會讓它輸出一些信息,特別是一些大型的程序,我們通過這些信息可以了解程序的運行情況,python提供了一個日志模塊logging,它可以把我們想要的信息全部保存到一個日志文件中,方便查看。

import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

屏幕上打印:
WARNING:root:This is warning message
默認情況下,logging將日志打印到屏幕,日志級別為WARNING;
日志級別大小關系為:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,當然也可以自己定義日志級別。

3. 在pytest中用logging代替print
我們現在來看看在pytest的測試用例里面用logging的輸出代替print,有什么不同。
slowTest_logging.py

import time
import logging

logging.basicConfig(level=logging.DEBUG)

def test_1():
    log = logging.getLogger('test_1')
    time.sleep(1)
    log.debug('after 1 sec')
    time.sleep(1)
    log.debug('after 2 sec')
    time.sleep(1)
    log.debug('after 3 sec')
    assert 1, 'should pass'


def test_2():
    log = logging.getLogger('test_2')
    time.sleep(1)
    log.debug('after 1 sec')
    time.sleep(1)
    log.debug('after 2 sec')
    time.sleep(1)
    log.debug('after 3 sec')
    assert 0, 'failing for demo purposes'

運行結果如下,log信息的顯示是不是可讀性更好了呢。可是pytest還是要等所有的結果都運行完畢才完全輸出到屏幕上,沒法看到實時的運行情況。比如現在要測試一個新的image,不知道quality如何,如果測試用例非常多,測試人員就得一直等,也許前面的一些測試用都失敗就可以停止執行了。那怎么實現實時顯示呢?請看方法4。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py .F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
---------------------------- Captured stderr call -----------------------------
DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
===================== 1 failed, 1 passed in 6.37 seconds ======================
C:\Users\yatyang\PycharmProjects\pytest_example>pytest -s slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py DEBUG:test_1:after 1 sec
DEBUG:test_1:after 2 sec
DEBUG:test_1:after 3 sec
.DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
===================== 1 failed, 1 passed in 6.18 seconds ======================

4. pytest用logging和–capture=no實現實時輸出log信息
請自己去運行下面的程序吧,可以看到該程序是實時輸出當前測試用例執行的情況。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -s slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: {'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py DEBUG:test_1:after 1 sec
DEBUG:test_1:after 2 sec
DEBUG:test_1:after 3 sec
.DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
===================== 1 failed, 1 passed in 6.20 seconds ======================

5.總結
在寫自動化測試用例時,添加有用的log信息是非常有必要的。比如在初期的調試過程,能夠一旦運行有問題,就可以獲取到精確的調試信息。后期在穩定的運行中,其他測試人員來運行也可以很容易上手,所以大家一定要重視測試用例的調試信息。
通過本文,應該知道如何用pytest,logging和–capture=no實現運行測試用例的實時輸出所有的log信息。

3, 代碼覆蓋率-多用在單元測試中

在這里插入圖片描述
一,上篇(---- pytest-cov)
簡介:
pytest-cov 是pytest的一個插件,其本質也是引用 python coverage 庫 用來統計代碼覆蓋率。以下這篇文章只供理解,真實項目的話,我們都是用api調用接口的,所以真實項目使用會更復雜一些,這個待下次說明。

另外說明:coverage 是在覆蓋率是語句覆蓋的一種,不能對你的邏輯做判讀,真實意義的話,需要多結合項目本身,這個覆蓋率數據沒有很強大說服力,不要盲目追求。
一般來說:
路徑覆蓋率 > 判定覆蓋 > 語句覆蓋

安裝

pip install pytest-cover

安裝完后有

py.test -h 可以看到多了以下的用法,說明安裝成功:

coverage reporting with distributed testing support:

范例
新建三個文件,cau.py 與test_conver.py 在同一個目錄code下。run.py文件在上一級目錄pp下。
代碼關系如下。
在這里插入圖片描述

1.新建函數文件cau.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
def cau (type,n1, n2):

    if type==1:
        a=n1 + n2
    elif type==2:
        a = n1 - n2
    else:
        a=n1 * n2
    return a

2.新建test_conver.py測試文件:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from code.cau import cau
class Test_cover:
    def test_add(self):
        a=cau(1,2,3)
        assert a==3

3.新建執行腳本run.py

#!/usr/bin/env ```python
# -*- coding: utf-8 -*-
import pytest

if __name__=='__main__':
	pytest.main(["--cov=./code/" ,"--cov-report=html","--cov-config=./code/.coveragerc"] )  # 執行某個目錄下case

說明:–cov參數 后面接的是測試的目錄 (經給測試,不能指定某個特定的文件。),程序代碼跟測試腳本必須在同一個文件下。 --cov-report=html 生成報告 ,只需要python run.py 就可以運行

coveragerc  意思是跳過某些腳本的覆蓋率測試。此處跳過test_cover.py文件跟init文件。

內容如下:

[run]
omit =
	tests/*
	 */__init__.py
	*/test_cover.py

結果
生成完后可以直接點擊indexhtml
在這里插入圖片描述
可以看到如下的執行情況,綠色代表運行,紅色代表未被執行,自己檢查下代碼邏輯,可以得出該結果是正確的。
在這里插入圖片描述
二:下篇(— coverage.py api)
使用pytest-cov 無法統計用 api調用服務的測試腳本所覆蓋率,但大部分的項目基本也是使用api調用。所以我們額外需要使用coverage.py api 來統計。
當你安裝pytest-cov時,已經默認安裝了coverage 這個庫。

服務啟動
要想掃描到代碼,必須在服務啟動的時候要插入coverage相關配置。
我這邊是flask 啟動的,所以在flask啟動的代碼上添加,如下:

if __name__ == '__main__':
    cov = Coverage()
    cov.start()  # 開始檢測代碼
    print ("qidong")
    app.run(debug=True, host='0.0.0.0',port=9098)  #原本只有這一行
    cov.stop()  # 停止紀錄
    print ("guanbi")
    cov.save()  # 保存在 .coverage 中
    print ("save")
    cov.html_report()  # 生成 HTML 報告

原本我們是python xx.py 這樣啟動,但現在不可以。
需要改成這樣,source 表示目錄,xx表示執行文件。

coverage run --source='/xxx/' xx.py

啟動運行圖如下:
在這里插入圖片描述
然后調用你的自動化腳本(自動化腳本是直接調的該服務提供的api 。)
在這里插入圖片描述
自動化如果正常運行,能看到運行的請求

以上說明你的腳本跟服務是沒問題的

ctr-c停掉該腳本后,最后顯示save,如果顯示”Coverage.py warning: No data was collected. (no-data-collected)“ 說明的服務運行方式有問題,coverage 服務沒有運行到你代碼

報告生成
輸入以下命令

coverage report

在這里插入圖片描述
最后一步最后輸入

coverage html

這樣就可以省 html 文件了。

導出在window上看,具體點擊某個文件,點擊run,你可以看到綠色的就是運行的。但有問題是,你會發現有些代碼應該是要被執行,但卻沒有被執行。所以coverage的數據准不准很難說。

4,allure測試報告框架

pytest+allure現在都是結合jenkins來搞的,很簡單相信大家都會,不會的老哥可以去看我的另一個博客持續集成里的有寫

5,定制報告

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
定制報告
Feature: 標注主要功能模塊
Story: 標注Features功能模塊下的分支功能
Severity: 標注測試用例的重要級別
Step: 標注測試用例的重要步驟
Issue和TestCase: 標注Issue、Case,可加入URL

1、Features定制詳解

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
def test_case_01():
    """ 用例描述:Test case 01 """
    assert 0
    
@allure.feature('test_module_02')
def test_case_02():
    """ 用例描述:Test case 02 """
    assert 0 == 0
    
    
if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加feature,Report展示見下圖。
在這里插入圖片描述

2、Story定制詳解

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
@allure.story('test_story_01')
def test_case_01():
    """ 用例描述:Test case 01 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
def test_case_02():
    """ 用例描述:Test case 02 """
    assert 0 == 0


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加story,Report展示見下圖。
在這里插入圖片描述

3、用例標題和用例描述定制詳解

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest

@allure.feature('test_module_01')
@allure.story('test_story_01')
#test_case_01為用例title
def test_case_01():
    """ 用例描述:這是用例描述,Test case 01,描述本人 """
    #注釋為用例描述
    assert 0

if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加用例標題和用例描述,Report展示見下圖。
在這里插入圖片描述

4 、Severity定制詳解
Allure中對嚴重級別的定義:
1、 Blocker級別:中斷缺陷(客戶端程序無響應,無法執行下一步操作)
2、 Critical級別:臨界缺陷( 功能點缺失)
3、 Normal級別:普通缺陷(數值計算錯誤)
4、 Minor級別:次要缺陷(界面錯誤與UI需求不符)
5、 Trivial級別:輕微缺陷(必輸項無提示,或者提示不規范)

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case_01():
    """ 用例描述:Test case 01 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('critical')
def test_case_02():
    """ 用例描述:Test case 02 """
    assert 0 == 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('normal')
def test_case_03():
    """ 用例描述:Test case 03 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('minor')
def test_case_04():
    """ 用例描述:Test case 04 """
    assert 0 == 0

    
if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Severity,Report展示見下圖。
在這里插入圖片描述

5、Step定制詳解

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest

@allure.step("字符串相加:{0},{1}")     
# 測試步驟,可通過format機制自動獲取函數參數
def str_add(str1, str2):
    if not isinstance(str1, str):
        return "%s is not a string" % str1
    if not isinstance(str2, str):
        return "%s is not a string" % str2
    return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Step,Report展示見下圖。
在這里插入圖片描述
6、Issue和TestCase定制詳解

# -*- coding: utf-8 -*-
# @Time : 2018/8/17 上午10:10
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.step("字符串相加:{0},{1}")     # 測試步驟,可通過format機制自動獲取函數參數
def str_add(str1, str2):
    print('hello')
    if not isinstance(str1, str):
        return "%s is not a string" % str1
    if not isinstance(str2, str):
        return "%s is not a string" % str2
    return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
@allure.issue("http://www.baidu.com")
@allure.testcase("http://www.testlink.com")
def test_case():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

添加Issue和TestCase,Report展示見下圖。
在這里插入圖片描述
8、attach定制詳解

 file = open('../test.png', 'rb').read()
 allure.attach('test_img', file, allure.attach_type.PNG)

在報告中增加附件:allure.attach(’arg1’,’arg2’,’arg3’):
arg1:是在報告中顯示的附件名稱
arg2:表示添加附件的內容
arg3:表示添加的類型(支持:HTML,JPG,PNG,JSON,OTHER,TEXTXML)

添加attach參數,Report展示見下圖。
在這里插入圖片描述

6,pytest運行指定用例

隨着軟件功能的增加,模塊越來越多,也意味用例越來越多,為了節約執行時間,快速得到測試報告與結果,在工作中可以通過運行指定用例,達到快速執行用例

例子目錄
在這里插入圖片描述
spec_sub1_modul_test.py

#coding: UTF-8
import pytest

def test_004_spec():
    assert 1==1
def test_005_spec():
    assert True==False
    
class Test_Class():
    def test_006_spec(self):
        assert 'G' in "Goods"

spec_sub2_modul_test.py

#coding: UTF-8
import pytest

def test_007_spec():
    assert 1==1
def test_008_spec():
    assert True==False
    
class Test_Class():
    def test_009_spec(self):
        assert 'G' in "Goods"

spec_001_modul_test

#coding: UTF-8
import pytest

def test_001_spec():
    assert 1==1
def test_002_spec():
    assert True==False
    
class Test_Class():
    def test_003_spec(self):
        assert 'H' in "Hell,Jerry"

運行指定模塊

if __name__ == '__main__':
    pytest.main("-v -s spec_001_modul_test.py")

運行批量文件夾(運行當前文件夾包括子文件夾所有用例)

#coding: UTF-8
import pytest
if __name__ == '__main__':
    pytest.main("-v -s ./")

運行指定文件夾(subpath1目錄下面所有用例)

#coding: UTF-8
import pytest
if __name__ == '__main__':
    pytest.main("-v -s subpath1/")

運行模塊中指定用例 (運行模塊中test_001_spec用例)

if __name__ == '__main__':
    pytest.main("-v -s spec_001_modul_test.py::test_001_spec")

運行class中指定的用例(運行模塊中Test_Class類test_003_spec方法)

if __name__ == '__main__':
   pytest.main("-v -s spec_001_modul_test.py::Test_Class::test_003_spec")

模糊匹配運行用例(匹配當前目錄下面包含)

if __name__ == '__main__':
    #運行spec_001_modul_test模塊中用例名稱包含spec的用例
    pytest.main("-v -s -k spec spec_001_modul_test.py")
    #運行當前文件夾匹配Test_Class的用例,類文件下面的用例
    pytest.main('-s -v -k Test_Class')

7,按重要性級別進行一定范圍測試

在這里插入圖片描述
此標記用來標識測試用例或者測試類的級別,分為blocker,critical,normal,minor,trivial5個級別,下面們把測試用例按級別標記,並查看一下測試報告
在這里插入圖片描述

8, 為測試添加詳說明@allure.description;@allure.title;

1.title case標題

可以自定義用例標題,標題默認為函數名.

@allure.title

# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest


@allure.title("用例標題0")
def test_0():
    pass

@allure.title("用例標題1")
def test_1():
    pass


def test_2():
    pass

執行效果:
在這里插入圖片描述

  1. 說明

可以添加測試的詳細說明,以便根據需要為報告閱讀器提供盡可能多的上下文。

兩種方式:@allure.description 提供描述字符串的裝飾器

@allure.description_html 提供一些HTML在測試用例的描述部分 (待研究)

# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.title("用例標題0")
@allure.description("這里是對test_0用例的一些詳細說明")
def test_0():
    pass

@allure.title("用例標題1")
def test_1():
    pass

@allure.title("用例標題2")
def test_2():
    pass

在這里插入圖片描述

9, 鏈接@allure.link @allure.issue @allure.testcase

在這里插入圖片描述
@allure.link @allure.issue @allure.testcase

# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.feature('這里是一級標簽')
class TestAllure():

    @allure.title("用例標題0")
    @allure.story("這里是第一個二級標簽")
    @pytest.mark.parametrize('param', ['青銅', '白銀', '黃金'])
    def test_0(self, param):
        allure.attach('附件內容是: '+param, '我是附件名', allure.attachment_type.TEXT)

    @allure.title("用例標題1")
    @allure.story("這里是第二個二級標簽")
    def test_1(self):
        allure.attach.file(r'E:\Myproject\pytest-allure\test\test_1.jpg', '我是附件截圖的名字', attachment_type=allure.attachment_type.JPG)

    @allure.title("用例標題2")
    @allure.story("這里是第三個二級標簽")
    @allure.issue('http://baidu.com', name='點擊我跳轉百度')
    @allure.testcase('http://bug.com/user-login-Lw==.html', name='點擊我跳轉禪道')
    def test_2(self):
        pass

執行結果如下:
在這里插入圖片描述

七, 單元自動化測試pytest和allure在測試中應用 自動執行

1, 單元測試測試報告展示

在這里插入圖片描述

2, conftest中編寫driver,范圍session,使用 addfinalizer在測試結束后關閉瀏覽器

在這里插入圖片描述

3, 前端自動化測試-百度搜索功能實戰演示

在這里插入圖片描述
報告可以展示許多不同類型的附件,用來補充測試,步驟等信息

allure.attach(body, name, attachment_type, extension)

body - 要寫入文件的原始內容。

name - 包含文件名的字符串

attachment_type- 其中一個allure.attachment_type值

extension - 提供的將用作創建文件的擴展名

或者 allure.attach.file(source, name, attachment_type, extension)

source - 包含文件路徑的字符串。

# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.feature('這里是一級標簽')
class TestAllure():

    @allure.title("用例標題0")
    @allure.story("這里是第一個二級標簽")
    @pytest.mark.parametrize('param', ['青銅', '白銀', '黃金'])
    def test_0(self, param):
        allure.attach('附件內容是: '+param, '我是附件名', allure.attachment_type.TEXT)

    @allure.title("用例標題1")
    @allure.story("這里是第二個二級標簽")
    def test_1(self):
        allure.attach.file(r'E:\Myproject\pytest-allure\test\test_1.jpg', '我是附件截圖的名字', attachment_type=allure.attachment_type.JPG)

    @allure.title("用例標題2")
    @allure.story("這里是第三個二級標簽")
    @allure.severity(allure.severity_level.NORMAL)
    def test_2(self):
        pass

執行結果如下:
  在這里插入圖片描述
  在這里插入圖片描述
  在這里插入圖片描述

4,源碼:Github:https://github.com/linda883/py_techDemo

5, CI/CD使用jenkins進行持續集成

在Jenkins集成相信大家都會就不講了,或者看我的持續集成博客
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

 

 


免責聲明!

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



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