关键字 开发-02 关键字驱动执行yaml用例

发布时间 2023-11-24 11:36:03作者: dack_deng

1. 封装request运行方法

我们将测试数据写到yaml文件中,通常会使用pytest框架parametrize参数化的方式读取yaml文件数据生成测试用例,于是我们可以根据这个思路来开发。

# utils/request_session.py
import requests
import re
from requests import Response

class ParserError(Exception):
    pass

class HttpSession(requests.Session):

    def __init__(self, base_url: str=None, timeout=10):
        super().__init__()
        self.base_url = base_url
        self.timeout = timeout

    @staticmethod
    def check_url(base_url: str, url: str) -> str:
        """ 拼接base_url 和 url 地址"""
        if re.compile(r"(http)(s?)(://)").match(url):
            return url
        elif base_url:
            if re.compile(r"(http)(s?)(://)").match(base_url):
                return f"{base_url.rstrip('/')}/{url.lstrip('/')}"
        else:
            raise ParserError("base url do yo mean http:// or https://!")

    def send_request(self, method, url, base_url=None, **kwargs) -> Response:
        """判断是否有传base_url, 没有则用公共的base_url"""
        url = self.check_url(base_url, url) if base_url else self.check_url(self.base_url, url)
        return self.request(method, url, timeout=self.timeout, verify=False, **kwargs)
# 获取yaml文件的模块,utils/read_file.py
import yaml
from pathlib import Path

def read_yaml(file_path: Path):
    """
    读取 yaml 数据,转 python 类型
    :param file_path:
    :return: dict
    """
    with open(file_path, 'r', encoding='utf-8') as fp:
        data = yaml.safe_load(fp)
    return data

if __name__ == '__main__':
    file_path = Path(__file__).parent.parent.joinpath('data', 'login.yml')
    res = read_yaml(file_path)
    print(res.items())
    print(type(res))  # -->dict

1.1 配置base_url

通常我们不会将base_url写进yaml文件中,yaml文件中也只是放url的相对路径。
全局环境地址切换使用 base_url 来实现,先安装插件:> pip install pytest-base-url
项目根目录新增 pytest.ini 文件,写入以下内容:

[pytest]
filterwarnings =
ignore::DeprecationWarning
ignore::urllib3.exceptions.InsecureRequestWarning
base_url=http://124.20.143.221:8201

2. 根据关键字运行用例

如何根据关键字去运行用例呢,这里的核心思想就是使用反射机制来运行关键字。

2.1 什么是反射

反射的本质是通过字符串去调用某对对象的方法/属性,或者调用模块中的函数等。python中提供了四个重要的方法.

  • getattr获取对象属性/对象方法
  • hasattr判断对象是否有对应的属性及方法
  • delattr删除指定的属性
  • setattr为对象设置内容

2.2 getattr获取对象属性/方法

如下代码块,里面有属性和方法,我们正常调用是先实例化再调用对象和方法。

class Page:
  name = "hello"
  des = "world"
  
  def click():
    print("click button")
  
  def clear(self):
    print("clear")

  def fill(self, text):
    print(f"input text: {text}")
if __name__ == '__main__':
  p = Page()
  print(p.name)
  print(p.click())

当我们想批量操作的时候,比如只需要知道关键字"click","clear","fill" 就可以调用对应的方法了.

p = Page()
# 获取对象属性
name = getattr(p, "name")
print(name)
# 调用对象方法
getattr(p, "click")()
# 方法带参数
getattr(p, "fill")("hello world")

我们在调用之前事先不知道有对应方法,所以先判断后调用,hasattr判断对象是否有对应的属性及方法。

p = Page()
# 先判断后调用
if hasattr(p, "click"):
  getattr(p, "click")()

delattr 删除指定的属性: delattr(p, "click") print(p.click)
setattr 为对象设置内容, 可以动态添加属性和方法: setattr(p, 'age', 22) print(getattr(p, 'age'))
`
了解了这个原理后,我们就可以来编写我们的模块

# utils/run.py

"""利用反射运行关键字"""
class RunByKey:
    def __init__(self, session):
        self.session = session

    @staticmethod
    def name(value):
        print(f'用例名称:{value}')

    def request(self, value: dict):
        print(f"执行request: {value}")
        res = self.session.send_request(**value)
        return res

    def run(self, data: dict):
        for key, value in data.items():
            if hasattr(self, key):
                res = getattr(self, key)(value)
                print(f"=========当前的key:{key}")
                if key == "request":
                    print(f"执行结果:{res.text}")
            else:
                print(f"关键字未定义: {key}")

接下来我们编写test_login.py来运行这个yaml文件中的用例。我们yaml文件中写了2条测试用例,base_url在pytest.ini中已经定义了

test_login:
  name: 登录成功
  request:
    url: /api/v1/auth/login
    method: POST
    json:
      username: "admin"
      password: "Admin@22"

test_login2:
  name: 登录失败
  request:
    url: /api/v1/auth/login
    method: POST
    json:
      username: "admin"
      password: "Admin@2233"
import pytest
from utils import read_file
from pathlib import Path
from utils.request_session import HttpSession
from utils.run import RunByKey

# 获取文件路径
file_path = Path(__file__).parent.joinpath('data', 'login.yml')

@pytest.mark.parametrize('name, value', read_file.read_yaml(file_path).items())
def test_login(name, value, base_url):
    print(f"测试用例名称: {name}")
    print(f"测试数据: {value}")  # data ---dict
    print(f"base_url: {base_url}")
    s = HttpSession(base_url=base_url)
    run = RunByKey(s)
    run.run(value)

运行结果如下图所示:

现在可以使用关键字来运行yaml文件的测试用例了,但是呢,这是各个参数都是写死的传入,如果我们需要引入变量,该怎么传入呢,后面将会解决这个问题。