Pytest和Allure測(cè)試框架-超詳細(xì)版+實(shí)戰(zhàn)6

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

1, pytest中l(wèi)ogging的應(yīng)用

在這里插入圖片描述

2, 日志及級(jí)別的含義

在這里插入圖片描述

自動(dòng)化測(cè)試用例的調(diào)試信息非常有用,可以讓我們知道現(xiàn)在的運(yùn)行情況到,執(zhí)行到哪步以及相應(yīng)的出錯(cuò)信息等,可以在pytest里面,有時(shí)并不會(huì)輸出所有信息,比如默認(rèn)情況下pass的測(cè)試用例是沒有print輸出的。本文將介紹如何在pytest里面實(shí)時(shí)顯示所有的log信息。

  1. 用print輸出log信息
    slowTest_print.py1. 用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'

運(yùn)行上述程序,pytest會(huì)capture所有的輸出,保存直到所有的測(cè)試用例都執(zhí)行結(jié)束,并且只輸出那些失敗的測(cè)試用例的信息,對(duì)于成功的測(cè)試用例,沒有print的信息顯示。
從下面的運(yùn)行結(jié)果,如果需要查看test_1()的運(yùn)行情況,沒有l(wèi)og信息可看,print沒有顯示。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v slowTest_print.py

以用‘-s’參數(shù)或者 ‘–capture=no’,這樣就可以輸出所有測(cè)試用的print信息。但是pytest還是會(huì)等著所有的測(cè)試用例都執(zhí)行完畢才會(huì)顯示運(yùn)行結(jié)果??梢钥吹较旅娴膖est_1也顯示出print的相關(guān)信息。

C:\Users\yatyang\PycharmProjects\pytest_example>py.test --capture=no slowTest_print.py

  1. Python Logging用法
    一般情況下,一些程序的調(diào)試過程中我們會(huì)讓它輸出一些信息,特別是一些大型的程序,我們通過這些信息可以了解程序的運(yùn)行情況,python提供了一個(gè)日志模塊logging,它可以把我們想要的信息全部保存到一個(gè)日志文件中,方便查看。
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
默認(rèn)情況下,logging將日志打印到屏幕,日志級(jí)別為WARNING;
日志級(jí)別大小關(guān)系為:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,當(dāng)然也可以自己定義日志級(jí)別。

  1. 在pytest中用logging代替print
    我們現(xiàn)在來看看在pytest的測(cè)試用例里面用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'

運(yùn)行結(jié)果如下,log信息的顯示是不是可讀性更好了呢??墒莗ytest還是要等所有的結(jié)果都運(yùn)行完畢才完全輸出到屏幕上,沒法看到實(shí)時(shí)的運(yùn)行情況。比如現(xiàn)在要測(cè)試一個(gè)新的image,不知道quality如何,如果測(cè)試用例非常多,測(cè)試人員就得一直等,也許前面的一些測(cè)試用都失敗就可以停止執(zhí)行了。那怎么實(shí)現(xiàn)實(shí)時(shí)顯示呢?請(qǐng)看方法4。

C:\Users\yatyang\PycharmProjects\pytest_example>pytest slowTest_logging.py

  1. pytest用logging和–capture=no實(shí)現(xiàn)實(shí)時(shí)輸出log信息
    請(qǐng)自己去運(yùn)行下面的程序吧,可以看到該程序是實(shí)時(shí)輸出當(dāng)前測(cè)試用例執(zhí)行的情況。
    C:\Users\yatyang\PycharmProjects\pytest_example>pytest -s slowTest_logging.py

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

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

在這里插入圖片描述

一,上篇(---- pytest-cov)
簡(jiǎn)介:
pytest-cov 是pytest的一個(gè)插件,其本質(zhì)也是引用 python coverage 庫 用來統(tǒng)計(jì)代碼覆蓋率。以下這篇文章只供理解,真實(shí)項(xiàng)目的話,我們都是用api調(diào)用接口的,所以真實(shí)項(xiàng)目使用會(huì)更復(fù)雜一些,這個(gè)待下次說明。
一般來說:
路徑覆蓋率 > 判定覆蓋 > 語句覆蓋

安裝
pip install pytest-cover

安裝完后有

py.test -h 可以看到多了以下的用法,說明安裝成功:
coverage reporting with distributed testing support:

另外說明:coverage 是在覆蓋率是語句覆蓋的一種,不能對(duì)你的邏輯做判讀,真實(shí)意義的話,需要多結(jié)合項(xiàng)目本身,這個(gè)覆蓋率數(shù)據(jù)沒有很強(qiáng)大說服力,不要盲目追求。

范例
新建三個(gè)文件,cau.py 與test_conver.py 在同一個(gè)目錄code下。run.py文件在上一級(jí)目錄pp下。
代碼關(guān)系如下。


在這里插入圖片描述

1.新建函數(shù)文件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測(cè)試文件:

#!/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.新建執(zhí)行腳本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"] )  # 執(zhí)行某個(gè)目錄下case

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

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

內(nèi)容如下:

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

結(jié)果
生成完后可以直接點(diǎn)擊indexhtml


在這里插入圖片描述

可以看到如下的執(zhí)行情況,綠色代表運(yùn)行,紅色代表未被執(zhí)行,自己檢查下代碼邏輯,可以得出該結(jié)果是正確的。


在這里插入圖片描述

二:下篇(— coverage.py api)
使用pytest-cov 無法統(tǒng)計(jì)用 api調(diào)用服務(wù)的測(cè)試腳本所覆蓋率,但大部分的項(xiàng)目基本也是使用api調(diào)用。所以我們額外需要使用coverage.py api 來統(tǒng)計(jì)。
當(dāng)你安裝pytest-cov時(shí),已經(jīng)默認(rèn)安裝了coverage 這個(gè)庫。

服務(wù)啟動(dòng)
要想掃描到代碼,必須在服務(wù)啟動(dòng)的時(shí)候要插入coverage相關(guān)配置。
我這邊是flask 啟動(dòng)的,所以在flask啟動(dòng)的代碼上添加,如下:

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

原本我們是python xx.py 這樣啟動(dòng),但現(xiàn)在不可以。
需要改成這樣,source 表示目錄,xx表示執(zhí)行文件。

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

啟動(dòng)運(yùn)行圖如下:


在這里插入圖片描述

然后調(diào)用你的自動(dòng)化腳本(自動(dòng)化腳本是直接調(diào)的該服務(wù)提供的api 。)


在這里插入圖片描述

自動(dòng)化如果正常運(yùn)行,能看到運(yùn)行的請(qǐng)求

以上說明你的腳本跟服務(wù)是沒問題的

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

報(bào)告生成
輸入以下命令

coverage report

在這里插入圖片描述

最后一步最后輸入

coverage html

這樣就可以省 html 文件了。

導(dǎo)出在window上看,具體點(diǎn)擊某個(gè)文件,點(diǎn)擊run,你可以看到綠色的就是運(yùn)行的。但有問題是,你會(huì)發(fā)現(xiàn)有些代碼應(yīng)該是要被執(zhí)行,但卻沒有被執(zhí)行。所以coverage的數(shù)據(jù)準(zhǔn)不準(zhǔn)很難說。

4,allure測(cè)試報(bào)告框架

pytest+allure現(xiàn)在都是結(jié)合jenkins來搞的,很簡(jiǎn)單相信大家都會(huì),不會(huì)的老哥可以去看我的另一個(gè)博客持續(xù)集成里的有寫

5,定制報(bào)告

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

定制報(bào)告
Feature: 標(biāo)注主要功能模塊
Story: 標(biāo)注Features功能模塊下的分支功能
Severity: 標(biāo)注測(cè)試用例的重要級(jí)別
Step: 標(biāo)注測(cè)試用例的重要步驟
Issue和TestCase: 標(biāo)注Issue、Case,可加入U(xiǎn)RL

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、用例標(biāo)題和用例描述定制詳解

# -*- 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'])

添加用例標(biāo)題和用例描述,Report展示見下圖。


在這里插入圖片描述

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

# -*- 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}")     
# 測(cè)試步驟,可通過format機(jī)制自動(dòng)獲取函數(shù)參數(shù)
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}")     # 測(cè)試步驟,可通過format機(jī)制自動(dòng)獲取函數(shù)參數(shù)
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)

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

添加attach參數(shù),Report展示見下圖。


在這里插入圖片描述

6,pytest運(yùn)行指定用例

隨著軟件功能的增加,模塊越來越多,也意味用例越來越多,為了節(jié)約執(zhí)行時(shí)間,快速得到測(cè)試報(bào)告與結(jié)果,在工作中可以通過運(yùn)行指定用例,達(dá)到快速執(zhí)行用例

例子目錄


在這里插入圖片描述

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"

運(yùn)行指定模塊

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

運(yùn)行批量文件夾(運(yùn)行當(dāng)前文件夾包括子文件夾所有用例)

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

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

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

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

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

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

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

模糊匹配運(yùn)行用例(匹配當(dāng)前目錄下面包含)

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

7,按重要性級(jí)別進(jìn)行一定范圍測(cè)試

在這里插入圖片描述

此標(biāo)記用來標(biāo)識(shí)測(cè)試用例或者測(cè)試類的級(jí)別,分為blocker,critical,normal,minor,trivial5個(gè)級(jí)別,下面?zhèn)儼褱y(cè)試用例按級(jí)別標(biāo)記,并查看一下測(cè)試報(bào)告


在這里插入圖片描述

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

1.title case標(biāo)題
可以自定義用例標(biāo)題,標(biāo)題默認(rèn)為函數(shù)名.

@allure.title

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

import allure
import pytest

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

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

def test_2():
    pass

執(zhí)行效果:


在這里插入圖片描述
  1. 說明
    可以添加測(cè)試的詳細(xì)說明,以便根據(jù)需要為報(bào)告閱讀器提供盡可能多的上下文。

兩種方式:
@allure.description 提供描述字符串的裝飾器
@allure.description_html 提供一些HTML在測(cè)試用例的描述部分 (待研究)

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

import allure
import pytest

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

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

@allure.title("用例標(biāo)題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('這里是一級(jí)標(biāo)簽')
class TestAllure():

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

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

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

執(zhí)行結(jié)果如下:


在這里插入圖片描述

參考鏈接
https://blog.csdn.net/qq_42610167/article/details/101204066

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

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

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