pytest测试框架总结

pytest测试框架

特点:

1、非常容易上手,入门简单,文档丰富,文档中有很多参考实例

2、支持简单的单元测试和复杂的功能测试

3、支持参数化

4、执行测试用例过程中,支持跳过操作

5、支持重复执行失败的case

6、支持运行由Nose,unittest编写的测试case

7、pytest支持很多第三方插件

8、方便的和持续集成工具集成

1、pytest介绍及安装

  • pytest安装(3种方式)

    • 在线安装 pip install pytest

    • 离线安装方式 下载pytest离线安装包,并解压,然后在DOS下进入到解压的目录,然后执行

      python setup.py install

    • pycharm

  • 判断是否安装成功:

    • pip show pytest
    • pycharm

2、pytest类定义及方法定义及运行

  • pytest测试类的定义:类名必须是以Test开头

  • pytest测试方法的定义:方法名必须是以test开头

  • 执行:

    • 在pycharm中右击方法名或者类名可以直接执行对应测试类或者测试方法

  • 第二种运行方式: 通过pytest -s -v 测试文件名称 (-s 输出的用例输出的信息, -v输出的是执行的用例的类名以及方法名)

def add(a, b):
    return a + b


# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    def test_add_001(self):
        result = add(5, 8)
        print(result)

    def test_add_002(self):
        result = add(105, 9)
        print(result)
        
        
--D:\PycharmProjects\UItest\test_t>pytest -s -v test_001.py

3、pytest断言

  • pytest里面的断言方法就只有一个

    assert 表达式

def add(a, b):
    return a + b


# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result == 3    #判断相等
        assert result != 4    #判断不想等
        assert result        #判断为Ture
        #assert False          #判断为False
        #assert  "a" in "abc"   #判断包含
        #assert "a" not in "abc"  # 判断不包含
        #assert result is  None    # 判断是否为空
        assert result is not None    # 判断是否不为空

4、pytest方法级别的fixture

  • pytest方法级别的fixture是针对每个测试方法,在执行测试方法前会执行fixture初始化的操作,在执行完测试方法后,执行fixture销毁的操作
  • 初始化的操作方法: def setup(self): 方法来实现。----setup要小写
  • 销毁的操作方法: def teardown(self): 方法来实现。-----teardown要小写
import time

def add(a, b):
    return a + b

# 定义一个pytest类
class Test_add:

    def setup(self):
        print("测试用例开始执行时间",time.strftime("%Y-%m-%D-%M-%S"))

    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)

    def test_add_002(self):
        result = add(2, 2)
        print(result)

    def teardown(self):
        print("测试用例结束时间", time.strftime("%Y-%m-%D-%M-%S"))
        
        
        
======================== 2 passed, 1 warning in 0.04s =========================

Process finished with exit code 0
测试用例开始执行时间 2022-07-09  19:29:34
PASSED                               [ 50%]3
测试用例结束时间 2022-07-09  19:29:34
测试用例开始执行时间 2022-07-09  19:29:34
PASSED                               [100%]4
测试用例结束时间 2022-07-09  19:29:34

5、pytest类级别的fixture

fixture同通常用来对测试方法,测试函数,测试类和整个测试文件进行初始化或还原测试环境。

  • pytest 类级别的fifixture针对每个测试类的初始化和销毁的操作,可以放在以下两个方法中

    • 类级别初始化的方法: def setup_class(self):

    • 类级别销毁的方法: def teardown_class(slef):

      方法名称固定,不能修改。

fixture的方法必须写在测试类当中,不能写在测试类外面。

import time


def add(a, b):
    return a + b


# 定义一个pytest类
class Test_add:
    #添加类级别的初始化操作方法
    def setup_class(self):
        print("类开始执行时间", time.strftime("%Y-%m-%d  %H:%M:%S"))

    #添加类级别的销毁操作方法
    def teardown_class(self):
        print("类结束执行时间", time.strftime("%Y-%m-%d  %H:%M:%S"))

    def setup(self):
        print("测试用例开始执行时间",time.strftime("%Y-%m-%d  %H:%M:%S"))

    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)

    def test_add_002(self):
        result = add(2, 2)
        print(result)

    def teardown(self):
        print("测试用例结束时间", time.strftime("%Y-%m-%d  %H:%M:%S"))
        
        
================================== 2 passed in 0.03s==================================       
collected 2 items                                                                                                                                                                   
test_add_01.py::Test_add::test_add_001 
类开始执行时间 2022-07-09  20:02:27
        
测试用例开始执行时间 2022-07-09  20:02:27
3
PASSED测试用例结束时间 2022-07-09  20:02:27

test_add_01.py::Test_add::test_add_002 
测试用例开始执行时间 2022-07-09  20:02:27
4
PASSED测试用例结束时间 2022-07-09  20:02:27
        
类结束执行时间 2022-07-09  20:02:27



6:前置方法,后置方法

前置方法:

  • setup_function ---只对普通的方法有效,def test_XXX()
  • setup_method ----只对类内部的方法有效,class TestXXX ---def test_XXX(self)
  • setup_class ------只对类有效 并且要放在类内部
  • setup_module ----对py文件有效
    • 当脚本里有普通方法,有类方法混合时,都想用初始化,就用model,在当下的py脚本都是有效的

后置方法:

  • teardown_function
  • teardown_method
  • teardown_class
  • teardown_module

举例:

实验1:setup_function方法

  • -----只对普通的方法有效,def test_XXX()
def setup_function():
    print("setup_function():每个方法之前执行")

def teardown_function():
    print("teardown_function():每个方法之后执行")

def test_01():
    print("正在执行test1")

def test_02():
    print("正在执行test2")
    
    
data_test.py::test_01 
setup_function():每个方法之前执行
正在执行test1
PASSEDteardown_function():每个方法之后执行

data_test.py::test_02 
setup_function():每个方法之前执行
正在执行test2
PASSEDteardown_function():每个方法之后执行  
  • 如果.py文件中既有类又有方法,使用setup_function会是怎样的效果?

    ---只对普通的方法有效 对类中的方法无效

def setup_function():
    print("setup_function():每个方法之前执行")
def test_01():
    print("正在执行test1")
def test_02():
    print("正在执行test2")
def teardown_function():
    print("teardown_function():每个方法之后执行")

class Test_pytest():
    def test_03(self):
        print("类中的方法test3")
        
data_test.py::test_01 
setup_function():每个方法之前执行
正在执行test1
PASSED
teardown_function():每个方法之后执行

data_test.py::test_02 
setup_function():每个方法之前执行
正在执行test2
PASSED
teardown_function():每个方法之后执行

data_test.py::Test_pytest::test_03 
类中的方法test3
PASSED

实验2:setup_method方法

  • ----只对类内部的方法有效,class TestXXX ---def test_XXX(self)
class Test_setup():
    def setup_method(self):
        print("初始化方法")

    def test_01(self):
        print("测试方法1")
    def test_02(self):
        print("测试方法2")

    def teardown_method(self):
        print("结束方法")

        
data_test.py::Test_setup::test_01 
初始化方法
测试方法1
PASSED结束方法

data_test.py::Test_setup::test_02 
初始化方法
测试方法2
PASSED结束方法

实验3:setup_class方法

  • ----只对类有效 并且要放在类内部
class Test_setup():
    def setup_class(self):
        print("初始化方法")

    def test_01(self):
        print("测试方法1")
    def test_02(self):
        print("测试方法2")

    def teardown_class(self):
        print("结束方法")
        
        
data_test.py::Test_setup::test_01
初始化方法
测试方法1
PASSED
data_test.py::Test_setup::test_02 
测试方法2
PASSED
结束方法

实验4:setup_module方法

  • 当脚本里有普通方法,有类方法混合时,都想用初始化,就用module,在当下的py脚本都是有效的
def setup_module():
    print("setup_function():每个方法之前执行")
def test_01():
    print("正在执行test1")
def test_02():
    print("正在执行test2")
def teardown_module():
    print("teardown_function():每个方法之后执行")

class Test_pytest():
    def test_03(self):
        print("类中的方法test3")
        
data_test.py::test_01 setup_function():
每个方法之前执行

正在执行test1
PASSED
data_test.py::test_02 
正在执行test2
PASSED
data_test.py::Test_pytest::test_03 
类中的方法test3

PASSEDteardown_function():
每个方法之后执行

8、pytest配置文件

pytest的配置文件有固定的三个名称: pytest.ini tox.ini setup.cfg 这三个配置文件是放在项目的根目录下。

[pytest]              # 标识当前配置文件是pytest的配置文件
addopts = -s -v       # 标识pytest执行时增加的参数
testpaths = ./scripts     # 匹配搜索的目录
python_files = test_*.py    # 匹配测试文件
python_classes = Test*      # 匹配测试类
python_functions = test_*    # 匹配测试方法

一、Pytest常用插件

1、pytest测试报告

  • 安装pytest测试报告插件

    • 在线安装 pip install pytest-html
    • 离线安装
    • pycharm
  • 使用方法

addopts = -s -v --html=report/report.html


2、控制用例执行顺序

  • unittest测试用例执行顺序是根据测试方法名称的assicc码值的大小来的,值越小排在前面(a-z)

  • pytest 正常情况下是根据测试方法的从上到下的顺序来执行.

    • 可以通过 pytest-ordering 插件来控制pytest测试方法执行的顺序。
  • 安装:

    • 在线安装: pip install pytest-ordering
    • 离线安装: 下载对应的离线安装包,解压后,并进入到对应的目录,执行 python setup.py install
    • pycharm
  • 使用

    @pytest.mark.run(order=x) # x 表示的是整数,(既可以是负数也可以是正数)

    • 全为负数或者正数时,值越小,优先级越高
    • 既有正数,又有负数,那么正数优先级高 (2 -3 -1)
    • 没有确定执行顺序的用例优先于负数
@pytest.mark.last    # 设置用例最后执行

示例: 编写一个测试类,不用pytest-ordering,观察方法的执行顺序

示例2:方法名上面加上 @pytest.mark.run(order=x) 观察方法执行顺序

import time
import pytest

def add(a, b):
    return a + b

# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    @pytest.mark.run(order=5)
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result==3

    @pytest.mark.run(order=4)
    def test_add_002(self):
        result = add(2, 2)
        print(result)
        assert result==4

    @pytest.mark.run(order=3)
    def test_add_003(self):
        result = add(3, 2)
        print(result)
        assert result==5
        
============================= 3 passed in 0.05s =================================       
collected 3 items   

scripts/test_ordering.py::Test_add::test_add_003 5
PASSED
scripts/test_ordering.py::Test_add::test_add_002 4
PASSED
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED

3、失败重试

  • 安装:

    • 在线安装: pip install pytest-rerunfailures
    • 离线安装: 下载对应的离线安装包,解压后,并进入到对应的目录,执行 python setup.py install
    • pycharm
  • 使用:

    在addopts参数行中增加对应的参数项: --reruns 2

    当重复执行成功时,就不会再重复执行。

示例:将test_add_003断言改为失败 ini文件中addopts参数设置 --reruns 2 -

import time

import pytest


def add(a, b):
    return a + b


# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    @pytest.mark.run(order=5)
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result==3

    @pytest.mark.run(order=4)
    def test_add_002(self):
        result = add(2, 2)
        print(result)
        assert result==4

    @pytest.mark.run(order=3)
    def test_add_003(self):
        result = add(3, 2)
        print(result)
        assert result==4
        
collected 3 items                                                                                                                                                                   
scripts/test_ordering.py::Test_add::test_add_003 5
RERUN
scripts/test_ordering.py::Test_add::test_add_003 5
RERUN
scripts/test_ordering.py::Test_add::test_add_003 5
FAILED
scripts/test_ordering.py::Test_add::test_add_002 4
PASSED
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED

=================== short test summary info =============================================
FAILED scripts/test_ordering.py::Test_add::test_add_003 - assert 5 == 4
================== 1 failed, 2 passed, 2 rerun in 0.12s =================================

二、 pytest高级用法

1、跳过

1.1直接跳过

@pytest.mark.skip(reason=None)

  • reason表示的是跳过的原因

1.2满足条件跳过

@pytest.mark.skipif(condition, reason=None)

  • condition 表示是跳过的条件

可以在测试类和测试方法上使用

  • 示例1:在测试类使用直接跳过-----@pytest.mark.skip("版本已更新,不需要在进行测试")
import time
import pytest

def add(a, b):
    return a + b
# 定义一个pytest类

@pytest.mark.skip("版本已更新,不需要在进行测试")
class Test_add:
    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result==3

    def test_add_002(self):
        result = add(2, 2)
        print(result)
        assert result==4

    def test_add_003(self):
        result = add(3, 2)
        print(result)
        assert result==5
        
collected 3 items                                                                                                                                                                   
scripts/test_ordering.py::Test_add::test_add_001 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_003 SKIPPED (版本已更新,不需要在进行测试)
============================== 3 skipped in 0.06s ======================================
  • 示例1:在测试方法使用直接跳过-----@pytest.mark.skip("版本已更新,不需要在进行测试")
import time
import pytest

def add(a, b):
    return a + b

# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result==3

    @pytest.mark.skip("版本已更新,不需要在进行测试")
    def test_add_002(self):
        result = add(2, 2)
        print(result)
        assert result==4

    def test_add_003(self):
        result = add(3, 2)
        print(result)
        assert result==5
        
collected 3 items                                                                                                                                                                   
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (版本已更新,不需要在进行测试)
scripts/test_ordering.py::Test_add::test_add_003 5
PASSED
============================== 2 passed, 1 skipped in 0.05s =============================
  • 示例3:测试类使用-------满足条件跳过

    version = 21
    @pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例")
    
    import time
    import pytest
    
    def add(a, b):
        return a + b
    # 定义一个pytest类
    
    version = 21
    @pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例")
    class Test_add:
        # 定义一个pytest方法
        def test_add_001(self):
            result = add(1, 2)
            print(result)
            assert result==3
    
        def test_add_002(self):
            result = add(2, 2)
            print(result)
            assert result==4
    
        def test_add_003(self):
            result = add(3, 2)
            print(result)
            assert result==5
            
     collected 3 items                                                                                   
    scripts/test_ordering.py::Test_add::test_add_001 SKIPPED (大于2.0版本不需要在执行次用例)
    scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (大于2.0版本不需要在执行次用例)
    scripts/test_ordering.py::Test_add::test_add_003 SKIPPED (大于2.0版本不需要在执行次用例)
    ================================ 3 skipped in 0.05s ================================
    
  • 示例4:测试方法使用-------满足条件跳过

version = 21
@pytest.mark.skipif(version>20,reason="大于2.0版本不需要在执行次用例")
import time
import pytest

def add(a, b):
    return a + b
    
# 定义一个pytest类
class Test_add:
    # 定义一个pytest方法
    def test_add_001(self):
        result = add(1, 2)
        print(result)
        assert result==3

    version = 21
    @pytest.mark.skipif(version > 20, reason="大于2.0版本不需要在执行次用例")
    def test_add_002(self):
        result = add(2, 2)
        print(result)
        assert result==4

    def test_add_003(self):
        result = add(3, 2)
        print(result)
        assert result==5
        
collected 3 items                                                                                                                                                                   
scripts/test_ordering.py::Test_add::test_add_001 3
PASSED
scripts/test_ordering.py::Test_add::test_add_002 SKIPPED (大于2.0版本不需要在执行次用例)
scripts/test_ordering.py::Test_add::test_add_003 5
============================ 2 passed, 1 skipped in 0.07s ============================

2、数据的参数化

pytest参数化实现:

  • @pytest.mark.parameterize(argnames, argvalues)
    • argnames 表示是 参数名字,字符串格式, 多个参数之间由逗号隔开 "username, password"
    • argvalues 表示的是参数化的数据 列表格式
      • [("13700001111","123124"),("13800011111","123456")]
      • argname的参数个数要与argvalues里面的测试数据的个数要相同,否则会报错。

示例:

import pytest

def add(x, y):
    return x + y

class TestAdd:
    @pytest.mark.parametrize("x,y,expect", [(1, 2, 3), (2, 2, 4), (3, 2, 5)])
    def test_add_01(self, x, y, expect):
        result = add(x, y)
        assert expect == result
        
collected 3 items

scripts/test_add_02.py::TestAdd::test_add_01[1-2-3] PASSED
scripts/test_add_02.py::TestAdd::test_add_01[2-2-4] PASSED
scripts/test_add_02.py::TestAdd::test_add_01[3-2-5] PASSED
================================= 3 passed in 0.05s =====================================

三、数据驱动

1、数据驱动介绍

概念:通过测试数据来驱动测试用例的执行。

1.1 数据驱动特点

  • 数据驱动本身不是一个工业级标准的概念,因此在不同的公司都会有不同的解释。
  • 可以把数据驱动理解为一种模式或者一种思想。
  • 数据驱动技术可以将用户把关注点放在对测试数据的构建和维护上,而不是直接维护脚本,可以利用同样的过程对不同的数据输入进行测试。
  • 数据驱动的实现要依赖参数化的技术。

1.2 数据驱动方式

  • 直接定义在测试脚本中(简单直观,但代码和数据未实现真正的分离,不方便后期维护)
  • 从文件读取数据,如JSON、excel、xml、txt等格式文件
  • 从数据库中读取数据
  • 直接调用接口获取数据源
  • 本地封装一些生成数据的方法

1.3 json读取文件回顾

数据驱动实战一

1.安装:pip install ddt

2,导包

from ddt import ddt,data,unpack

3,使用ddt装饰器---示例

from ddt import ddt,data,unpack

#构造测试数据
def build_data():
    pass

@ddt
class TPShopLogin2(unittest.TestCase):
    
    @data(*build_data())
    @unpack
    def test01_login(self):
        pass
    
#build_data()是定义的读取json文件的方法, 相当于是一个二维列表,[[{"username":"mike"}],		    [{"username":"mike11"}]]-----需要用unpack解包 

#@unpack 解包  只能解包一次  解出来是一组一组数据[{"username":"mike"}]  [{"username":"mike"}]  	每一组数据还是一个列表 ,需要配合*进行两次解包
#*build_data()  调用函数时,函数名前面加*,表示对结果进行一次解包
#在配合@unpack  就可以进行两次解包

示例;

import json
from ddt import ddt,data,unpack
import requests
import unittest
from parameterized import parameterized

#构造测试数据
def build_data():
    test_data=[]
    file="../data/login.json"
    with open(file,encoding="utf-8") as f:
        json_data=json.load(f)
        for case_data in json_data:
            username=case_data.get("username")
            password = case_data.get("password")
            verify_code = case_data.get("verify_code")
            status_code = case_data.get("status_code")
            status = case_data.get("status")
            msg = case_data.get("msg")
            test_data.append((username,password,verify_code,status_code,status,msg))
        # print("test_data".format(username,password,verify_code,status_code,status,msg))
        print(test_data)
    return    test_data



@ddt
class TPShopLogin2(unittest.TestCase):
    def setUp(self):
        #实例化session对象
        self.session=requests.Session()
        #定义验证码接口url地址
        self.url_verify="http://localhost/index.php?m=Home&c=User&a=verify"
        #定义登录接口url地址
        self.url_login="http://localhost/index.php?m=Home&c=User&a=do_login"

    def tearDown(self):
        #关闭session对象
        self.session.close()

    @data(*build_data())
    @unpack
    def test01_login(self,username,password,verify_code,status_code,status,msg):
        #发送验证码请求并断言
        response=self.session.get(url=self.url_verify)
        self.assertEqual(200,response.status_code)
        self.assertIn("image",response.headers.get("Content-Type"))

        #发送登录请求并断言
        login_data={
            "username":username,
            "password":password,
            "verify_code":verify_code
        }
        response=self.session.post(url=self.url_login,data=login_data)
        print(response.json())
        self.assertEqual(status_code,response.status_code)
        self.assertEqual(status,response.json().get("status"))
        self.assertIn(msg,response.json().get("msg"))


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

DDT的实现原理(重点)

ddt在使用是非常简洁,也就是两个装饰器

  • @ddt 这个装饰器装饰测试类
  • @data 这个装饰器装饰用例方法并传入测试数据

这两个装饰器实现的效果就是:根据传入的用例数据自动生成用例。

具体是怎么实现的呢?其实实现思路就两个步骤:

  • 第一步:把传进来的用例数据保存起来
  • 第二步:遍历用例数据,没遍历一条数据就动态的给测试类添加一个用例方法。

@data:做的是第一步,将转入的测试数据保存起来

@ddt:做的是第二步,遍历测试用例,给测试类动态添加用例方法

@ddt
class TestLogin(unittest.TestCase):
    @data(11,12)
    def test_login(self,item)
    	pass
    
分析上面的代码,首先是调用data装饰器函数,把用例数据11,12 当成参数传入进去,然后返回一个可调用对象(函数)
,在次调用返回的函数并把用例方法传入进去。

五.关联+传递参数

1.关联+传递独立参数组成的业务

处理方法:

  • @pytest.fixture
  • parametrize方法
  • 使用全局配置文件conftest.py
  • 全局变量

示例:

1.1---@pytest.fixture

  • pytest不支持这种向普通的方法参数传递的过程,需要加上pytest标签说明--@pytest.fixture

1.1.1同一个脚本内部参数传递

  • 加上@pytest.fixture后 可以传递了
@pytest.fixture()
def test_case01():
    num1=6
    return num1

def test_case02(test_case01):
    num2=test_case01
    print("从方法1传递的值",num2)
    
Process finished with exit code 0
从方法1传递的值 6
PASSED
  • 如何传递一组值--列表
@pytest.fixture()
def test_case03():
    dataList=[1,2,3,4]
    return dataList

def test_case04(test_case03):
    test_case03.append(5)
    print("从方法3传入的列表",test_case03)
    
Process finished with exit code 0
从方法3传入的列表 [1, 2, 3, 4, 5]
PASSED
  • 如何传递一组值--字典
@pytest.fixture()
def test_case03():
    dataform={"username":"zhangsan","password":"123456"}
    return dataform

def test_case04(test_case03):
    print("从方法3传入的列表",test_case03)
    
Process finished with exit code 0
从方法3传入的列表 {'username': 'zhangsan', 'password': '123456'}
PASSED

1.1.2不同脚本之间参数传递

  • 从另外一个文件传递参数

其他文件先返回参数

需要参数的文件先导包

#文件2--返回参数的
import pytest

@pytest.fixture()
def test_case01():
    num1=60
    return num1
#**********************************************************************************

#文件1--需要传递参数的
from script.data_test_02 import test_case01

def test_case05(test_case01):
    num5=test_case01
    print("从其他文件通过fixture传入的数据",num5)
    
Process finished with exit code 0
从其他文件通过fixture传入的数据 60
PASSED

1.2--@pytest.mark.parametrize

结合参数化标签来传递参数

  • pytest参数化不能值转一个值,否则会报错
@pytest.mark.parametrize('num',(1))
def test_case07(num):
    print(num)
    
    
  --要多个值才行
@pytest.mark.parametrize('num',(1,2))
def test_case07(num):
    print(num)
#文件2--返回参数的
def test_case01():
    list=[1,2,3]
    return list

#文件1--传递参数的
from script.data_test_02 import test_case01

@pytest.mark.parametrize('num',test_case01())
def test_case06(num):
    num6=num
    print("从其他文件通过parametrize传入的数据",num6)
    
Process finished with exit code 0
PASSED从其他文件通过parametrize传入的数据 1
PASSED从其他文件通过parametrize传入的数据 2
PASSED从其他文件通过parametrize传入的数据 3
PASSED

1.3使用全局配置文件conftest.py

  • 结合配置文件conftest.py文件,这样就解决了引用/导包的麻烦
from script.data_test_02 import test_case01

通过公共的配置文件传递conftest.py

  • conftest.py是pytest特有的本地测试配置文件

1.先在配置文件 中conftest.py文件中定义需要返回参数的方法---所有脚本都可以调用这个方法

2,其他文件直接引用,不需要导包

1.4全局变量

  • 当前脚本所有方法都要用的,可以使用全局变量
  • 其他脚本要是要全局变量,需要先引用
global_list=[1,2,3]

def test_case02():
    print("全局变量",global_list)
    
    
Process finished with exit code 0
全局变量 [1, 2, 3]
PASSED

小结:

1、在当前脚本内部需要参数传递,就使用fixture

2、偶发性的需要使用其他脚本的参数

  • 如果已经设置fixture------引入该文件,用fixture方法进行参数传递
  • 或者使用普通函数方法传递-----结合parametrize

3、大批量的脚本需要使用相同的测试数据----数据放在conftest.py中----所有当前项目的脚本都可以直接使用,不需要引入文件

4、当前脚本需要传递某些公共的参数,不想定义fixture-----使用全局变量即可,

六.Allure测试报告

目标:

  1. 能够将项目生成 allure 报告

  2. 能够在 allure 报告上添加测试步骤

  3. 能够在 allure 报告上添加测试描述

  4. 能够在 allure 报告上添加严重级别

1. allure安装

  • 在线安装 pip install allure-pytest
  • 离线安装
  • pycharm安装

2. allure运行脚本生成结果文件

allure使用步骤:

  • 要在pytest.ini 配置文件中的addopts项中,增加一项:
--alluredir report

#report 表示的是生成报告数据存放的目录
# 添加行参数 
addopts = -s --alluredir report 
# 文件搜索路径 
testpaths = ./scripts 
# 文件名称 
python_files = test_*.py 
# 类名称 
python_classes = Test* 
# 方法名称 
python_functions = test_*
  • 在终端执行pytest命令 ,运行脚本
  • 程序运行结束后,会在项目的report目录中生成一些json文件

3. 将测试结果文件转成 html

安装:

  1. https://bintray.com/qameta/generic/allure2 下载 allure-2.6.0.zip

  2. 解压缩到一个目录(不经常动的目录)

  3. 将压缩包内的 bin 目录配置到 path 系统环境变量

  4. 右键我的电脑 - 属性 - 高级设置 - 环境变量 - 找到系统环境变量的path项 - 增加 allure到bin 目录

  5. 在命令行中敲 allure 命令,如果提示有这个命令,即为成功

使用步骤:

在保证项目中的 report 目录下有 json 文件的时候,执行以下步骤。

    1. 进入 report 上级目录执行命令
allure generate report/ -o report/html --clean
    1. report 目录下会生成 html 文件夹,html 下会有一个 index.html ,右键用浏览器打开即可。

4.疑问和解答

1、addopts = -s --alluredir report 中的 --alluredir report 是什么意思?

  • --alluredir 后面的 report 为测试结果文件输出的目录名
  • 如果希望目录名叫 result 那么可以将命令行参数改为 --alluredir result

2、allure generate report/ -o report/html --clean 是什么意思?

  • report/ 表示测试结果文件所在的目录
  • -o 表示 output 输出
  • report/html 表示将 index.html 报告生成到哪个文件夹

七、allure语pytest结合

1.添加测试步骤

应用场景 :

一套登录流程需要至少三个步骤,输入用户名,输入密码,点击登录。我们可以通过添加测试步 骤,让这些步骤在报告中进行体现

使用方式:

@allure.step(title="测试步骤001")

例如:在操作层中的方法上加上 @allure.step(title="测试步骤001") 装饰器

2. 添加图片描述

应用场景 :

如果我们想将某些操作过后的结果展现在报告上,可以使用添加图片描述的方法。

使用方式 在需要截图的地方添加如下代码:

allure.attach(driver.get_screenshot_as_png(), "截图", allure.attachment_type.PNG)


#截图
allure.attach(self.driver.get_screenshot_as_png(), "更新成功截图", allure.attachment_type.PNG)

3. 添加严重级别

应用场景 :

在工作中,我们会向开发人员提交很多 bug ,不同的 bug 优先级也应当不同,打开程序就崩溃, 和关于软件的页面错了一个字。就这两者而言,崩溃肯定更严重,也更需要开发人员优先修复。那 么,我可以将这些 bug 的优先级展示在报告当中。

使用方式 :

 @allure.severity(allure.severity_level.BLOCKER) 

在测试脚本中,增加装饰器 @allure.severity(allure.severity_level.BLOCKER)

参数有五个,也对应不同的优先级,只需要将最后一个词替换即可。

  1. BLOCKER 最严重

  2. CRITICAL 严重

  3. NORMAL 普通

  4. MINOR 不严重

  5. TRIVIAL 最不严重


posted @   mike002  阅读(1106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示