pytest_2

 

fixture夹具

 

 

conftest.py

  1.  scope="session"必须写在conftest.py里
  2. conftest.py为固定写法,不可修改名字
  3. 使用conftest.py文件方法无需导入
  4. 函数作用于当前文件夹及下属文件夹

 

 利用fixture写前置和后置

@pytest.fixture(scope="function",autouse=True)
def func():
    print("我是前置步骤")
    yield ""#加上yield后面就能写后置步骤了,“白”可以去掉,在这里只是想说yield能传东西出去,与return相比,传出东西后后续步骤依然会执行
    print("我是后置步骤")

 

 

参数化

 

parametrize

import pytest

# 单参数,单次循环
@pytest.mark.parametrize("a", ["单参数"])
def test_parametrize(a):
    print("我是" + a)

# 单参数,多次循环
#每赋值一次,运行一条测试用例
@pytest.mark.parametrize("name", ["安其拉","黄忠","大乔"])
def test_parametrize(name):
    print('我是' + name)
"""
多参数:
注意!只要参数数量大于1,则每一组参数对应的值都应在[]内打上()/[]
"""
#两个参数,[]内打上()元组
@pytest.mark.parametrize("name,word", [("安其拉","火烧屁屁咯"),("黄忠","周日被我射熄火了")])
def test_parametrize(name,word):
    print(f'{name}的台词是{word}')
#两个参数,[]内打上[]列表
@pytest.mark.parametrize("name,word", [["安其拉","火烧屁屁咯"],["黄忠","周日被我射熄火了"]])
def test_parametrize(name,word):
    print(f'{name}的台词是{word}')

 

#[]内打上{}字典。参数值为字典形式,只能是一个参数
@pytest.mark.parametrize("name", [{'names':"安其拉"},{'names':"黄忠"}])
def test_parametrize(name):
    print(name['names'])

"""
两个参数用字典的话,像上面那样取值就会报错
@pytest.mark.parametrize("name,word", [{'name':"安其拉",'word':"火烧屁屁咯"},{'name':"黄忠",'word':"周日被我射熄火了"}])
def test_parametrize(name,word):
    print(name['name'],word['word'])
--------------------------------------------------------------------------------------
只能像下面那样取值,但这不就回归只有一个参数了吗_(:з」∠)_,所以字典格式的话大概就只支持一个参数吧
@pytest.mark.parametrize("hero", [{'name':"安其拉",'word':"火烧屁屁咯"},{'name':"黄忠",'word':"周日被我射熄火了"}])
def test_parametrize(hero):
    print(hero['name'],hero['word'])
"""
@pytest.mark.parametrize("hero", [{'name':"安其拉",'word':"火烧屁屁咯"},{'name':"黄忠",'word':"周日被我射熄火了"}])
def test_parametrize(hero):
    print(hero['name'],hero['word'])

多个参数化,即参数化叠加时,运行测试用例如下图会得出执行4个用例:因为x中的每个元素都与y中的每个元素组合了一次

 

yaml

 

 

 Python中像字符串、布尔值、int等,都属于纯量。

 

 装PyYAML包

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyYAML
#data.yaml
person:
- name: 上海-${random_name()}-测试组
age: ${age()}
sex: 男
- name: 上海-${random_name()}-测试组
age: ${age()}
sex: 男
hero:
  name: 安其拉
  word: 火焰是我最喜欢的玩具
  hp: 445.5

hero2: {name: 安其拉, word: 火焰是我最喜欢的玩具, hp: 445.5}
#hero=hero2

heros_name:
  - 安其拉
  - 黄忠
  - 小乔

heros:
  - name: 黄忠
    word: 周日被我射熄火了
    hp: 440

heros_name_list:
  - - 安其拉
    - 黄忠
    - 小乔
heros_name_word:
- - 黄忠
- 周日被我射熄火了
- - 安其拉
- 火焰是我最喜欢的玩具
mobile_belong_post:
#手机号,appkey
- [13456755448,0c818521d38759e1]

mobile_belong_get:
#手机号,appkey
- [13456755448,0c818521d38759e1]
- [13000000000,0c818521d38759e1]
import yaml
#1.打开yaml文件,限定编码方式,防止中文乱码。此处使用相对路径。

f = open("../config/data.yaml", encoding="utf-8")
#2.读取yaml文件
data = yaml.safe_load(f)
print(data)
print(data['hero'])
print(data['hero2'])
print(data['heros_name'])
print(data['heros'])
print(data['heros_name_list'])
#然后右键运行这个文件

 python解析yaml

读取可以直接用: yaml.safe_load(f)
写入数据:yaml.dump(data=old_value, stream=f, allow_unicode=True, sort_keys=False)
#data:写入的数据, stream:文件, allow_unicode=True:遵循unicode编码, sort_keys=False:不设置的话默认为Ture指依据26个字母来给内容排序,False的话就会按照追加的顺序进行排序

yaml和parametrize参数化结合

注意:在 Python 中,相对路径是相对于当前工作目录而言的,而不是相对于代码文件所在的路径。
因此,在不同的文件中调用相同的代码时可能会出现路径错误。
绝对路径:它是描述从盘符开始到目标文件位置的完整路径。绝对路径虽然不会在其他文件调用时产生路径错误但过于死板,文件本身稍微改动下位置就不行了
所以,另一种方法是使用 os.path 模块动态获取文件路径

所以,用os.path改写上面的读yaml文件代码

#utils/read_data.py

import yaml,os

#视频上以逗号隔开拼接的路径,如下行,但直接用路径符也可以,如下下行
#path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),"config","data.yaml")
path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),"config/data.yaml")
def read_data():
    # 1.打开yaml文件,限定编码方式,防止中文乱码
    f = open(path, encoding="utf-8")
    # 2.读取yaml文件
    data = yaml.safe_load(f)
    return data

get_data = read_data()

 然后参数化

"""
testcases/test_parametrize_yaml.py, 在这个文件中调用上个文件读取的yaml数据进行参数化
单参数多次循环取出三个测试数据,[安其拉,黄忠,小乔],运行三条测试用例
双参数多次循环取出两组测试数据,[[黄忠,周日被我射熄火了],[安其拉,火焰是我最喜欢的玩具]]
"""
import pytest
from utils.read_data import get_data

# 单参数多次循环
@pytest.mark.parametrize("name", get_data['heros_name'])
def test_parametrize_02(name):
    print(name)

# 双参数多次循环
@pytest.mark.parametrize("name, word", get_data['heros_name_word'])
def test_parametrize_03(name, word):
    print(name, word)

 利用python自带函数eval(str)会自动运行str表达式实现yaml文件内用函数,安装Faker库造假数据

"""
utils/yaml_utils.py
涉及python自带函数
isinstance(data,dict)——-————判断数据是否为该类型
for key,value in data.items(): ——————字典独有的
str(value)———————————————————将各种值转换为字符串
eval(str(value))————————eval()里只能是字符串格式,但若字符串里有表达式/函数,会自动运行输出,如eval('1+2')————3,是个int
str(value).index('$') 字符串的索引/下标,运行完是int,字符串的下标从0开始数,所以字符串的长度=字符串最后一个下标数字+1
str(value)[start+1:end] 字符串的切片就是通过索引(索引:索引:步长)截取字符串的一段,形成新的字符串(取出来的原则就是顾头不顾腚,所以想取出来的时候去掉头就需要在开始的索引+1)。
len(str)——————获得字符串的长度数字
random.randint(10, 100)
"""
import random

def func_yaml(data):
    if isinstance(data,dict):
        for key,value in data.items():
            if '${' and '}' in str(value):
                start = str(value).index('$')
                end = str(value).index('}')
                func_name = str(value)[start+2:end]
                data[key] = str(value)[0:start]+str(eval(func_name))+ str(value)[end+1:len(str(value))]
                print(len(str(value)))
    return data
"""
安装Faker库 
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Faker
可以生成各种各样的伪造数据,如:姓名、身份证、手机号、银行卡
"""
from faker import Faker

fake = Faker(locale="zh-CN")
def random_name():
    return fake.name()

def age():
    return random.randint(10, 100)

if __name__ == '__main__':
    data = {'name': '上海-${random_name()}-测试', 'age':'${age()}', 'sex': ''}
    print(func_yaml(data))
   
#testcases/test_person.py ,结合参数化
import pytest

from utils.read_data import get_data
from utils.yaml_util import func_yaml

@pytest.mark.parametrize("data",get_data["person"])
def test_person(data):
    print(func_yaml(data))

 

 利用python反射: getattr(实例化类,'类的函数名')(函数的参数)实现yaml文件内用函数

如标题的 getattr() ,getattr(ExtractUtil(),'get_extract_value')(func_params)     通过‘函数名’获取成员方法/启动成员方法

还可以通过‘类变量’获取类变量,以及通过‘成员变量’获得成员变量

getattr大概指南如下:具体查看https://zhuanlan.zhihu.com/p/576254496
class Person():
  # 定义类变量
  guoJi = "china"
  def __init__(self,name,age,id):
    self.name = name
    self.age = age
    self.id = id  
def my_info(self,English): my_name = self.name + English
print(my_name)
# 创建类的对象 xiao_wang = Person("小王",23,"101010") print(Person.guoJi) # 反射获取类变量 print(getattr(Person, 'guoJi')) # 反射获取成员变量 print(getattr(xiao_wang,"name")) # 反射获取成员方法,返回方法是一个引用地址,要想执行该方法,需要在后面加上小括号 getattr(xiao_wang,"my_info")(English)

 

代码分层

 

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple configparser

 

posted @ 2023-08-28 23:58  云啊云的囤粮地  阅读(3)  评论(0编辑  收藏  举报