Pytest自动化测试简要介绍

一、pytest基础

1、什么是单元测试框架

单元测试指的是在软件开发测试中,针对软件的最小单位(函数、方法)进行正确性的检查测试。

2、单元测试框架主要做什么?

  1. 测试发现:从多个文件里面去找到我们测试用例(如何找?:按照一定的命名规则)
  2. 测试执行:按照一定的顺序和规则去执行。并生成结果
  3. 测试判断:通过断言判断预期结果和实际结果的差异
  4. 测试报告:统计测试进度,耗时,通过率,生成测试

3、单元测试框架和自动化测试框架的关系

单元测试框架:只是目动化测试框架中的组成部分之一

pom设计模式:只是目动化测试框架中的组成部分之一。

除此以外,自动化测试框架还包括:

数据驱动
关键字驱动
全局配置文件的封装
日志监控
selenium,requests二次封装
断言
报告邮件
……

4、pytest简介

  1. pytest是一个非常成熟的python的单元框架,比unittest更灵活,容易上手
  2. pytest可以和selenium,requests,appium结合实现web自动化,接口自动化,app自动化.
  3. pytest可以实现测试用例的跳过以及reruns失败用例重试。
  4. pytest可以和allure生成非常美观的测试报告。
  5. pytest可以和Jenkins持续集成。
  6. pytest有很多非常强大的插件,并且这些插件能够实现很多的实用的操作。
    • pytest-html(生成html格式的自动化测试报告)
    • pytest-xdist 测试用例分布式执行。多CPU分发
    • pytest-ordering 用于改变测试用例的执行顺序
    • pytest-rerunfailures用例失败后重跑
    • allure-pytest 用于生成美观的测试报告

python批量安装插件:

创建requirements.txt文件,在该文件中输入想要安装的插件名称

使用pip指令:pip install -r requirements.txt

5、pytest测试用例的默认发现规则

  1. py文件必须以test_开头或者以_test结尾
  2. 需要被测试的类必须以Test开头,并且不能有__init__()方法
  3. 需要被测试的方法必须以test开头

只是默认的规则,可以在pytest.ini配置文件中自定义规则

6、pytest测试用例的启动方式(常见)

  1. 主函数模式

    if __name__ == '__main__':
        pytest.main()
        #运行所有测试用例,不管是不是本py文件中的用例
    

    pytest.main()后面可以跟参数

    • -s:表示输出调试信息,包括print打印的信息

    • -v:显示更详细的信息(两个参数可以一起用)

    • 跟某个.py文件名/文件夹路径/nodeid:只启动指定的py文件/指定文件夹下的py文件/制定方法或函数

      nodeid:py文件路径::函数名 py文件路径名::类名::方法名

    • -n: 用多线程运行测试用例(线程数目可以自行设置)

    • –reruns=n:运行失败的用例会再重试n次

    • -x:若有用例测试失败,则停止整个测试流程。

    • –maxfail=n:出现n个失败用例就停止整个流程。

    • -k “str”:只运行名称包含”str“的测试方法。

    • –html ./report (报告文件的保存路径):生成测试报告

    if __name__ == '__main__':
        pytest.main(['-vs','test_login.py'])  #注意参数列表要加[]
    
    if __name__ == '__main__':
        pytest.main(['-vs','./interface_testcase'])
    
    if __name__ == '__main__':
        pytest.main(['-vs','./interface_testcase.test_interface::test_demo_fun'])
    
  2. 命令行模式

    直接在终端中运行pytest命令,会运行所有测试用例。

    与主函数模式一样,可以添加参数

    pytest -vs test_login.py
    
    pytest -vs ./test_case -n 2  //设置了两个线程
    
  3. 通过pytest.ini配置文件运行(实际工作中最常用的)

    位置:一般放在根目录下

    编码:ANSI编码方式

    作用:改变pytest的默认行为。不管是命令行模式还是主函数模式,都会去读取这个配置文件。

7、测试用例执行顺序

默认情况:从上到下

自定义设置执行顺序:利用注解@pytest.mark.run(需要第三方库pytest-ordering)

@pytest.mark.run(order=2)
def test_01(self):
    print("第一个方法")
    
@pytest.mark.run(order=1)
def test_02(self):
    print("第二个方法")
    
#运行时按照设置的order的顺序,会先执行test_02

8、pytest如何分组执行用例

现在ini配置文件中设置分组

markers = 
	xxx1:组1的名称/解释
	xxx2:组2的名称/解释
	xxx3:组3的名称/解释
	……

将某个测试方法归为某个组:添加注解

@pytest.mark.xxx(组名)
def test_demo_01(self):
	pass

运行指定的组的全部用例:在运行命令中添加参数 :-m “xxx(组名)” 多个组之间用or连接

pytest -m "xxx"
pytest -m "xxx" or "yyy"

9、pytest跳过测试用例

  1. 无条件跳过用例

    @pytest.mark.skip(reson="跳过的原因")
    
  2. 有条件跳过

    @pytest,mark.skipif(条件表达式,'跳过的原因')
    

    例如

    age = 10
    
    @pytest.mark.skipif(age < 20,"年龄不足20岁")
    def test_demo_01(self):
    	pass
    

10、conftest.py文件

conftest.py是fixture函数的一个集合,可以理解为公共的提取出来放在一个文件里,然后供其它模块调用。不同于普通被调用的模块,conftest.py使用时不需要导入,Pytest会自动查找。

我们可以把许多fixture函数写到该文件中,这样fixture函数就不会分散到许多py文件中,方便我们管理。

二、pytest拓展

1、用例前后置处理(夹具 固件)

  1. setup/teardown和setup_class/teardown_class

    class Test_demo:
        
        def setup_class(self):
            #这个类执行之前运行的代码
        
    	def setup(self):
            #每个测试方法执行之前都会执行一遍的代码
        
        def test_demo_01(self):
            ……
            
        def teardown(self):
            ##每个测试方法执行之后都会执行一遍的代码
    	
        def setup_class(self):
            #这个类执行之后运行的代码
    
  2. 使用@pytest.fixture()实现部分用例的前后置

    fixture修饰器的参数解释:

    • scope:表示fun1的作用域,包括function(默认),class,moudle,package,session;当设置为class时,只有该类被执行时才会执行fun1.(类似于setup_class和teardown_class)。其他参数以此类推

    • params:参数化(支持列表、元组、字典列表、字典元组)

      @pytest.fixture(,params=[1,2,3,5])
      def fun1(request):
          print("这是前置函数的内容")
          return request.param
      
    • autouse:是否自动执行

    • ids:启用参数化时,为传入的数值赋一个变量名

    • name:为被#pytest.fixture修饰的函数设置一个别名

    @pytest.fixture(scope='',params='',autouse='',ids='',name='')
    def fun1():
        print("这是前置函数的内容")
        yield
        print("这是后置函数的内容")
    
    #如何使用
    class Test_demo:
        
        def test_demo_01(self,fun1): 
            ……
    #在函数的参数列表中加入被fixture修饰的函数名,多个前置函数之间用逗号隔开,按照顺序执行各个前置
    #如果fixture修饰器中autouse设置为true,则不需要在参数列表中加入被fixture修饰的函数名,会自动执行
    
  3. 结合conftest和fixture实现全局前置

    conftest.py文件介绍:

    conftest.py是fixture函数的一个集合,可以理解为公共的提取出来放在一个文件里,然后供其它模块调用。不同于普通被调用的模块,conftest.py使用时不需要导入,Pytest会自动查找。

    conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了,如果放到某个package下,那就在该package内有效,可有多个conftest.py

2、断言

assert a==2  #assert后面直接跟上要判断的表达式,若表达式为true,则用例通过

3、allure插件生成报告

allure生成测试报告的步骤:

  • 在编写好的测试用例中添加allure装饰器函数
  • 在运行入口处编写运行allure执行命令
  • 查看生成的测试报告

常见的allure中的装饰器函数

这些装饰器函数写在测试类或者测试方法的开头;同一个测试类或测试函数可以添加多个装饰器函数

step和attachment比较特殊,他们位于方法内部而不是开头

函数说明
@allure.epic()项目名称
@allure.feature()模块名称
@allure.title()测试用例名称
@allure.description()测试用例描述(通常在此处写出预期结果)
allure.step描述测试步骤

示例:

@allure.epic("vshop")					#标记属于那个项目
@allure.feature("订单")					# 标记属于那个模块
@allure.story("订单列表")					#标记属于那个子模块
@allure.issue("http://localhost")
class TestOrder(unittest.TestCase):
 
    @allure.title("查询订单列表")						#标记测试用例
    @allure.description("显示该列表的所有数据")			# 标记用例的描述
    def test_order_list(self):
        with allure.step("1.进入我的订单列表页"):		#标记测试步骤
            self.order(self.driver)
        # 断言
        self.assertEqual("安全退出",self.reg.get_reg_msg(self.driver))
 

pytest集成allure后如何生成测试报告

  1. 若使用命令行启动pytest时,通过在pytest后面添加参数来生成allure报告:

    pytest --alluredir=./allure-results
    #其中`./allure-results`是指定的目录,用来存放生成的测试报告文件
    
  2. 若使用脚本调用pytest时,在参数列表中添加相应的参数:

    import pytest  
      
    if __name__ == '__main__':  
        pytest.main(['-vs', 'your_test_file.py', '--alluredir=./allure-results'])
    
  3. 执行完命令后,指定目录中生成的测试数据还不是html格式的,需要下列命令进行转换:

    allure generate ./allure-results -o ./allure-report --clean
    

    这条命令会读取allure-results目录下的数据,并在allure-report目录下生成HTML格式的测试报告。--clean参数用于在生成新报告之前清除allure-report目录中的旧文件。

4、python操作yaml文件

yaml文件基本语法:

  • 大小写敏感
  • #表示注释
  • 缩进表示层级关系

yaml三种数据结构:

  1. 字典:键值对的集合

    user: admin
    age: 18
    
    #字典嵌套字典
    data: 
      user: admin
      age: 18
    
  2. 列表

    name: 
      - 小红
      - 小明
      - 小白
    
    #列表嵌套字典
    data:
      - admin1: 123
      - admin2: 456
      - admin3: 789
    
  3. 字符串/布尔值/整数/浮点数/Null/时间/日期

使用PyYaml库操作yaml文件

  1. 读操作:使用yaml.safe_load()方法.该函数会解析YAML内容并返回一个Python对象(通常是字典或列表)。

    # 假设你有一个名为data.yaml的文件  
    with open('data.yaml', 'r') as file:  
        data = yaml.safe_load(file)  
      
    print(data)
    
  2. 写操作:使用yaml.dump()方法,它接受一个Python对象(通常是字典或列表)并将其序列化为YAML格式的字符串。你可以将这个字符串写入文件。

    data = {  
        'name': 'John Doe',  
        'age': 30,  
        'children': [  
            {'name': 'Jane Doe', 'age': 5},  
            {'name': 'Jim Doe', 'age': 7}  
        ]  
    }  
      
    with open('output.yaml', 'w') as file:  
        yaml.dump(data, file, allow_unicode=True)
    

    格式化写入:设置参数default_flow_style=False,这会生成一个更容易阅读的YAML文件,其中的键值对和列表使用缩进而不是方括号和花括号。

    with open('output_pretty.yaml', 'w') as file:  
        yaml.dump(data, file, allow_unicode=True, default_flow_style=False)
    

    写入中文:设置参数allow_unicode=True

    🔶**在一个pytest测试框架中,会专门定义一个yaml_Util.py类来进行各种yaml文件操作,其他py文件需要对yaml文件进行操作时直接调用即可。**这个文件中一般包括对yaml文件的读、写、清空等。

5、pytest实现接口关联

新建yaml文件,把需要用到的数据保存到yaml文件中;需要时再从yaml文件中读取。

此处yaml文件相当于postman中environment的作用

6、requests库中的测试会话session

创建requests的session对象,再用session发送get/post等请求,而不是直接发送

  1. 自动管理cookies:session对象会自动处理请求和响应中的cookies,可以自动保存和发送cookies,无需手动处理。这有助于保持用户登录状态等需要cookies支持的功能。
  2. 保持参数和状态:session对象可以在多个请求之间保持一些参数和状态,例如HTTP头、身份验证信息等。这样可以避免在每个请求中重复设置这些参数。
  3. 使用连接池:session对象使用底层的urllib3库,可以使用连接池来管理和重用HTTP连接,提高性能。
import requests  
  
# 创建一个session对象  
session = requests.Session()  
  
# 使用session对象发送GET请求  
response = session.get('https://www.example.com')  
print(response.text)  
  
# 假设登录接口需要POST请求,并且会返回登录后的cookies  
login_response = session.post('https://www.example.com/login', data={'username': 'user', 'password': 'pass'})  
  
# 登录成功后,使用同一个session对象发送其他请求,会自动携带登录后的cookies  
other_response = session.get('https://www.example.com/protected_resource')  
print(other_response.text)  
  
# 关闭session(可选,因为session对象会在Python程序结束时自动关闭)  
# session.close()

7、统一请求封装

目的:使多个py文件发送的请求都在同一个session下,方便自动管理cookie和统计相关信息

即不再是在每个测试类里都创建一个session对象,这样每个session只包含了一个测试类

实现方法:单独创建一个requests_util,.py文件,这个文件里的RequestUtil类有个session对象,是专门用来发送各种请求的。其他测试类想要发送请求,都来调用这个RequestUtil类中的方法

import requests

#封装意味着,这个方法要能够适应所有请求(各个种类的请求,以及各种参数的情况)
class RequestUtil:
    
    sess = requests.session()
    
    def send_request(self,method,url,datas=None,**kwargs):  #只有method和url是必填的
        method = str(method).lower()  #将传入的参数转化为字符串并且全部小写
        res = None  #用来接收返回结果的变量
        
        if method == 'get':
            res = RequestUtil.sess.request(method='get',url=url,params=datas,**kwagrs)
        elif method == 'post':
            if datas and isinstance(datas,dict):  #如果datas不为空且是一个字典
            	str_datas = json.dumps(datas)  #json.dumps可以把python对象转化为json字符串
            res RequestUtil.sess.request(method='post',url=url,data=str_datas,**kwargs)
        else:
            pass
        return res
    

8、yaml数据驱动封装

假设有一个存储测试用例的yaml文件cases.yaml

- case_id: 1  
  input:  
    number: 5  
  expected: 10  
  description: "Double the number"  
  
- case_id: 2  
  input:  
    number: 10  
  expected: 20  
  description: "Double the number again"

向yaml文件操作类yaml_Util.py中添加专门读取yaml测试用例的方法

def read_testcase(yaml_name):
    with open(os.getcwd() + '文件路径' + yaml_name,mode='r',encoding='utf-8') as f:
    	value = yaml.load(stream=f,Loader=yaml.FullLoader)
        return value

使用pytest.mark.parametrize装饰器来修饰测试方法

def double_number(number):  
    return number * 2  
  
@pytest.mark.parametrize("test_case", read_testcase(cases.yaml))  
def test_double_number(test_case):  
    assert double_number(test_case['input']['number']) == test_case['expected'], test_case['description']

我们使用pytest.mark.parametrize装饰器来遍历cases.yaml文件中的每个测试用例并取名test_case。每个测试用例都是一个字典,包含了inputexpecteddescription等键。我们调用double_number函数,并使用assert语句来验证输出是否符合预期。如果测试失败,description字段将作为失败消息的一部分显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值