Loading

Pytest测试框架(二)

Allure下载

https://github.com/allure-framework/allure2/releases

日志管理

  • 日志

           跟踪软件运行情况,记录执行过程,按不同级别显示

  • 日志级别

           logging提供了一组便利的函数,用来做简单的日志。它们是debug()、info()、warning()、error()、critical()

           默认等级是WARNING,这意味着仅仅这个等级及以上的才会反馈信息,除非logging模块被用来做其他事情

 

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,当然也可以自己定义日志级别。

  

在pytest中用logging来代替print

test_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'
E       AssertionError: failing for demo purposes
E       assert 0

test_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
------------------------------ Captured log call ------------------------------
DEBUG    test_2:test_logging.py:20 after 1 sec
DEBUG    test_2:test_logging.py:22 after 2 sec
DEBUG    test_2:test_logging.py:24 after 3 sec
=========================== short test summary info ===========================
FAILED test_Pytest.py::Test_01_Pytest::test_02_something_quick - AssertionErr...
FAILED test_Pytest.py::Test_01_Pytest::test_03_another - assert 1 == 0
FAILED test_Pytest.py::Test_01_Pytest::test_06_run - assert 10 == 11
FAILED test_logging.py::test_2 - AssertionError: failing for demo purposes
======================== 4 failed, 11 passed in 5.00s =========================

Process finished with exit code 0

 

pytest用logging和–capture=no实现实时输出log信息

pytest -s --capture=no test_logging.py
import pytest

if __name__ == '__main__':
    pytest.main(['-s','--capture=no','-n','5'])
test_logging.py:25: AssertionError
------------------------------ Captured log call ------------------------------
DEBUG    test_2:test_logging.py:20 after 1 sec
DEBUG    test_2:test_logging.py:22 after 2 sec
DEBUG    test_2:test_logging.py:24 after 3 sec
=========================== short test summary info ===========================
FAILED test_Pytest.py::Test_01_Pytest::test_06_run - assert (5 * 2) == 11
FAILED test_Pytest.py::Test_01_Pytest::test_03_another - assert (3 - 2) == 0
FAILED test_Pytest.py::Test_01_Pytest::test_02_something_quick - AssertionErr...
FAILED test_logging.py::test_2 - AssertionError: failing for demo purposes
======================== 4 failed, 11 passed in 4.94s =========================

Process finished with exit code 0

 

allure测试报告框架

 pytest+allure测试报告

简介

        python 主流自动化测试报告插件有三个:HTMLTestRunner、BeautifulReport 和 Allure。HTMLTestRunner是一个比较古老的报告模板,界面也不是很好看。BeautifulReport  界面很简洁,看起来也很直观,是一款比较不错的报告插件。如果你想提升一下你的level,让你的自动化测试报告变得高大上,那么请选择 Allure 。

  Allure 是一款轻量级的开源自动化测试报告生成框架。它支持绝大部分测试框架,比如 TestNG、Junit 、pytest、unittest 等。本文主要介绍 pytest 框架结合 Allure 生成 格式统一、美观的 测试报告。

pip install allure-pytest

  

下载安装allure

https://github.com/allure-framework/allure2/releases

 

下载后可以解压到硬盘,并设置环境变量

 

环境变量配置

path下加上  绝对路径 C:\allure-2.13.1\bin

 

cmd进入bin目录,运行:allure

 则安装成功

注:以上方法可行,本人不建议用以上方法

 

推荐方法: 

把allure文件夹放在项目目录下

 

 用代码获取allure.bat的绝对路径,来运行生成html报告

#!/usr/bin/env python
# coding=utf-8
import pytest
import allure
import os

file = os.path.abspath(__file__)    # 1、获取当前文件路径
path = file.split('run_all_case')[0]   # 2、获取共同路径部分
allurepath = path + 'allure-2.13.1/bin/allure.bat'  # 3、拼凑成需上传附件的绝对路径



if __name__ =="__main__":
    # 执行pytest单元测试,生成 Allure 报告需要的数据存在 /temp 目录
    pytest.main(['--alluredir', './temp'])
    # # 执行命令 allure generate ./temp -o ./report --clean ,生成测试报告
    os.system('%s generate ./temp -o ./report --clean' %allurepath)

 

定制报告

  • Feature: 标注主要功能模块
  • Story: 标注Features功能模块下的分支功能
  • Severity: 标注测试用例的重要级别
  • Step: 标注测试用例的重要步骤
  • Issue和TestCase: 标注Issue、Case,可加入URL

 

feature定制

# test_Pytest.py文件
# coding=utf-8

import pytest
import allure

class Test_01_Pytest():

    @pytest.mark.run(order=6)
    @allure.feature('test_Pytest')
    def test_01_send_http(self):
        print("----start----")
        print('test_01_send_http方法执行')
        pass  # perform some website test for your app

    @pytest.mark.run(order=5)
    @allure.feature('test_Pytest')
    def test_02_something_quick(self):
        print("test_02_something_quick方法执行")
        assert 'o' in 'live' # 报错

    @pytest.mark.run(order=4)
    @allure.feature('test_Pytest')
    def test_03_another(self):
        print("test_03_another方法执行")
        assert 3-2==0  # 报错

    @pytest.mark.run(order=3)
    @allure.feature('test_Pytest')
    def test_04_run(self):
        print("test_04_run方法执行")

    @pytest.mark.run(order=2)
    @allure.feature('test_Pytest')
    def test_05_run(self):
        print("test_05_run方法执行")

    @pytest.mark.run(order=1)
    @allure.feature('test_Pytest')
    def test_06_run(self):
        print("test_05_run方法执行")
        assert 5*2==11 # 报错


if __name__ == '__main__':
    pytest.main(['-v','--reruns','5','--reruns-delay','1','test_Pytest.py'])

story定制

# test_Pytest.py文件
# coding=utf-8

import pytest
import allure

class Test_01_Pytest():

    @pytest.mark.run(order=6)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4437 test_01_send_http")
    def test_01_send_http(self):
        print("----start----")
        print('test_01_send_http方法执行')
        pass  # perform some website test for your app

    @pytest.mark.run(order=5)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4439 test_02_something_quick")
    def test_02_something_quick(self):
        print("test_02_something_quick方法执行")
        assert 'o' in 'live' # 报错

    @pytest.mark.run(order=4)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4702 test_03_another")
    def test_03_another(self):
        print("test_03_another方法执行")
        assert 3-2==0  # 报错

    @pytest.mark.run(order=3)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4791 test_04_run")
    def test_04_run(self):
        print("test_04_run方法执行")

    @pytest.mark.run(order=2)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4792 test_05_run")
    def test_05_run(self):
        print("test_05_run方法执行")

    @pytest.mark.run(order=1)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4755 test_06_run")
    def test_06_run(self):
        print("test_05_run方法执行")
        assert 5*2==11 # 报错


if __name__ == '__main__':
    pytest.main(['-v','--reruns','5','--reruns-delay','1','test_Pytest.py'])

添加story,Report展示见下图

  

用例标题和用例描述定制详解

# test_Pytest.py文件
# coding=utf-8

import pytest
import allure

class Test_01_Pytest():

    @pytest.mark.run(order=6)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4437 test_01_send_http")
    # test_01_send_http为用例title
    def test_01_send_http(self):
        '''
        用例描述:这是用例描述,test_01_send_http,描述本人
        '''
        # 注释为用例描述
        print("----start----")
        print('test_01_send_http方法执行')
        pass  # perform some website test for your app

    @pytest.mark.run(order=5)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4439 test_02_something_quick")
    def test_02_something_quick(self):
        '''
        test_02_something_quick的用例描述
        '''
        print("test_02_something_quick方法执行")
        assert 'o' in 'live' # 报错

    @pytest.mark.run(order=4)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4702 test_03_another")
    def test_03_another(self):
        '''
        test_03_another 的用例描述
        '''
        print("test_03_another方法执行")
        assert 3-2==0  # 报错

    @pytest.mark.run(order=3)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4791 test_04_run")
    def test_04_run(self):
        '''
        test_04_run 的用例描述
        '''
        print("test_04_run方法执行")

    @pytest.mark.run(order=2)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4792 test_05_run")
    def test_05_run(self):
        '''
        test_05_run 的用例描述
        '''
        print("test_05_run方法执行")

    @pytest.mark.run(order=1)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4755 test_06_run")
    def test_06_run(self):
        '''
        test_06_run 的用例描述
        '''
        print("test_05_run方法执行")
        assert 5*2==11 # 报错


if __name__ == '__main__':
    pytest.main(['-v','--reruns','5','--reruns-delay','1','test_Pytest.py'])

 

Severity定制详解

Allure中对严重级别的定义:

  1. Blocker级别:中断缺陷(客户端程序无响应,无法执行下一步操作)
  2. Critical级别 :临界缺陷( 功能点缺失)
  3. Normal级别 :普通缺陷(数值计算错误)
  4. Minor级别   :次要缺陷(界面错误与UI需求不符)
  5. Trivial级别  :轻微缺陷(必输项无提示,或者提示不规范)
# test_Pytest.py文件
# coding=utf-8

import pytest
import allure

class Test_01_Pytest():

    @pytest.mark.run(order=6)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4437 test_01_send_http")
    @allure.severity(allure.severity_level.BLOCKER) # blocker、critical、normal、minor、trivial
    # test_01_send_http为用例title
    def test_01_send_http(self):
        '''
        用例描述:这是用例描述,test_01_send_http,描述本人
        '''
        # 注释为用例描述
        print("----start----")
        print('test_01_send_http方法执行')
        pass  # perform some website test for your app

    @pytest.mark.run(order=5)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4439 test_02_something_quick")
    @allure.severity(allure.severity_level.CRITICAL)
    def test_02_something_quick(self):
        '''
        test_02_something_quick的用例描述
        '''
        print("test_02_something_quick方法执行")
        assert 'o' in 'live' # 报错

    @pytest.mark.run(order=4)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4702 test_03_another")
    @allure.severity(allure.severity_level.NORMAL)
    def test_03_another(self):
        '''
        test_03_another 的用例描述
        '''
        print("test_03_another方法执行")
        assert 3-2==0  # 报错

    @pytest.mark.run(order=3)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4791 test_04_run")
    @allure.severity(allure.severity_level.MINOR)
    def test_04_run(self):
        '''
        test_04_run 的用例描述
        '''
        print("test_04_run方法执行")

    @pytest.mark.run(order=2)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4792 test_05_run")
    @allure.severity(allure.severity_level.TRIVIAL)
    def test_05_run(self):
        '''
        test_05_run 的用例描述
        '''
        print("test_05_run方法执行")

    @pytest.mark.run(order=1)
    @allure.feature('test_Pytest')
    @allure.story("CSCN 4755 test_06_run")
    @allure.severity(allure.severity_level.BLOCKER)
    def test_06_run(self):
        '''
        test_06_run 的用例描述
        '''
        print("test_05_run方法执行")
        assert 5*2==11 # 报错

if __name__ == '__main__':
    pytest.main(['-v','--reruns','5','--reruns-delay','1','test_Pytest.py'])

 

Step定制详解

# -*- coding: utf-8 -*-
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

@pytest.mark.run(order=14)
@allure.feature('test_Pytest')
@allure.story("CSCN 4435 test_case_step")
@allure.severity(allure.severity_level.TRIVIAL)
def test_case_step():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


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

  

 

Issue和TestCase定制详解

# -*- coding: utf-8 -*-

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

@pytest.mark.run(order=14)
@allure.feature('test_step')
@allure.story("CSCN 4435 test_case_step")
@allure.severity(allure.severity_level.TRIVIAL)
@allure.issue("https://blog.csdn.net/qq_42610167/article/details/101204066")
@allure.testcase("https://www.cnblogs.com/123blog/p/12499802.html")
def test_case_step():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


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

  

attach定制详解

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

作用:allure报告还支持显示许多不同类型的附件,可以补充测试结果;自己想输出啥就输出啥,挺好的

语法: allure.attach(body, name, attachment_type, extension) 

参数列表

  • body:要显示的内容(附件)
  • name:附件名字
  • attachment_type:附件类型,是 allure.attachment_type 里面的其中一种
  • extension:附件的扩展名(比较少用)

 

 

 

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

作用:传送文件

语法: allure.attach.file(source, name, attachment_type, extension) 

参数列表

  • source:文件路径,相当于传一个文件

试下两种效果:

# -*- coding: utf-8 -*-

import allure
import pytest
import os

file = os.path.abspath(__file__)    # 1、获取当前文件路径
path = file.split('test_step')[0]   # 2、获取共同路径部分
pngpath = path + 'data/porsche.png'  # 3、拼凑成需上传附件的绝对路径

@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

@pytest.mark.run(order=14)
@allure.feature('test_step')
@allure.story("CSCN 4435 test_case_step")
@allure.severity(allure.severity_level.TRIVIAL)
@allure.issue("https://blog.csdn.net/qq_42610167/article/details/101204066")
@allure.testcase("https://www.cnblogs.com/123blog/p/12499802.html")
def test_case_step():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'
    # print("jpgpath:",jpgpath)
    # file = open(jpgpath, 'rb').read()
    file = open(pngpath,'rb').read()
    allure.attach(file,'porsche',allure.attachment_type.PNG)
    allure.attach.file(pngpath, 'porsche', allure.attachment_type.PNG)


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

 

pytest运行指定用例

import pytest

# 运行指定模块
if __name__ == '__main__':
    pytest.main("-v -s spec_001_modul_test.py")


# 运行批量文件夹(运行当前文件夹包括子文件夹所有用例)
if __name__ == '__main__':
    pytest.main("-v -s ./")


# 运行指定文件夹(subpath1目录下面所有用例)
if __name__ == '__main__':
    pytest.main("-v -s subpath1/")


# 运行指定文件夹(subpath1目录下面所有用例)
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')

  

按重要性级别进行一定范围测试

--allure-severities=blocker # critical、normal、minor、trivial、blocker  按照case严重程度来执行用例

#!/usr/bin/env python
# coding=utf-8
import pytest
import allure
import os

file = os.path.abspath(__file__)    # 1、获取当前文件路径
path = file.split('run_all_case')[0]   # 2、获取共同路径部分
allurepath = path + 'allure-2.13.1/bin/allure.bat'  # 3、拼凑成需上传附件的绝对路径



if __name__ =="__main__":
    pytest.main(['--allure-severities=blocker','--alluredir', './temp'])
    os.system('%s generate ./temp -o ./report --clean' %allurepath)
posted @ 2020-05-29 17:52  Binzichen  阅读(271)  评论(0编辑  收藏  举报