1.接口自动化测试框架各层级目录说明

common-----基类目录,封装业务层和用例层需要基层的类和方法

libs------------业务层目录,项目功能模块接口业务代码

testcase------用例层目录,存放测试用例层的代码

config---------接口配置相关的数据和代码,比如路径,IP,用户名和密码登

datas----------存放测试数据的目录

log--------------日志打印目录

report----------测试报告目录

tool-------------存放辅助测试的一些方法,比如封装日子器方法、文件读取方法等函数

conftest.py----pytest框架fixture夹具配置文件

pytest.ini------pytest配置文件

1.1common基类目录

封装了请求请求基类和断言基类方法(增删改查)

"""
项目接口基类
"""
import inspect
import time
import traceback

from utils.handle_log import log
import requests
from configs.base_path import data_path
from utils.handle_yaml import get_yaml_data
from configs.hostconfig import HOST


class BaseAPI:
    """
    接口基类
    """

    # 定义请求头
    def __init__(self, Token=None):
        if Token:
            self.headers = {"Authorization": Token}
        else:
            self.headers = None
        # 读取api配置文件,业务层继承类的类名,方便自动取到configs目录下的apiConfig.yaml的类名
        self.data = get_yaml_data()[self.__class__.__name__]

    # 定义请求方法
    def get_request(self, params=None, json=None, files=None, urlData=None):
        try:
            apiName = inspect.stack()[1][3]  # 固定写法,某个函数调用get_request方法时会返回该函数的名称
            data = self.data[apiName]
            if urlData:
                resp = requests.request(method=data['method'], url=f'{HOST}' + data['url'] + f'{urlData}',
                                        headers=self.headers, params=params, json=json, files=files)
                log.info(f"{data}接口请求成功")
            else:
                resp = requests.request(method=data['method'], url=f'{HOST}' + data['url'],
                                        headers=self.headers, params=params, json=json, files=files)
                log.info(f"{data}接口请求成功")
            return resp.json()
        except Exception as error:
            # 错误日志
            log.error(traceback.format_exc())
            raise error

    # post接口请求方法
    def send_post(self, postData):  # postData请求参数
        return self.get_request(json=postData)

    # delete接口请求方法
    def send_delete(self, deleteData, inURL=False):  # deleteData删除请求参数,inURL=False判断是否为拼接URL传参
        if inURL:
            return self.get_request(urlData=deleteData)
        else:
            return self.get_request(params=deleteData)

    # update接口请求方法
    def send_put(self, putDate, inURL=False):  # updateData更新的请求参数,inURL=False判断是否为拼接URL传参
        if inURL:
            return self.get_request(urlData=putDate)
        else:
            return self.get_request(json=putDate)

    # get请求方法
    def send_get(self, getParams, inURL=False):  # getParams:请求参数,inURL=False判断是否为拼接URL传参
        if inURL:
            return self.get_request(urlData=getParams)
        else:
            return self.get_request(params=getParams)

    # 文件上传方法
    def send_upload(self, filePath):  # fileData请求数据
        return self.get_request(files={"file": open(f"{data_path}" + f"{filePath}", 'rb')})


class BaseAssert:
    """
    断言基类
    """

    @classmethod
    def assert_equal(cls, expData, realData):  # expData表示预期结果,realData表示实际结果,判断预期结果和实际结果是否相等
        try:
            assert expData == realData
        except Exception as error:
            # 日志
            log.error(traceback.format_exc())
            raise error

    @classmethod
    def assert_in(cls, result, array):  # result表示实际结果,array一个数组,断言结果是否在预期数组里
        try:
            assert result in array
        except Exception as error:
            # 日志
            log.error(traceback.format_exc())
            raise error

1.2libs业务类的封装

由于libs中的业务类已经继承了基类中的属性和方法,所以我们不需要再重新写业务类的属性和方法(除非该业务类存在独特的属性或者方法的时候,可以再重写)

from common.base import BaseAPI



class Login(BaseAPI):
    def login(self, login_data, getToken=False):
        resp = self.get_request(json=login_data)
        if getToken:
            return resp['data']['token']
        return resp

 1.3testcase存放测试用例代码

用例层代码使用了pytest和allure的一些装饰器对用例进行了管理和对allure报告进行定制,而且在用例层使用了数据驱动装饰器,实现了数据与代码的分离管理。

"""
登录模块用例层封装
"""
import allure
import pytest
from libs.login import Login
from utils.get_case_data import yaml_case_data
from common.base import BaseAssert


@pytest.mark.run(order=1)     # 排序执行
@allure.epic('电商后台管理系统')    # 项目名称
@allure.feature('登录模块')     # 模块名称
@pytest.mark.login       # 标记改类为‘登录’测试用例
class TestLogin(BaseAssert):
    @allure.story('登录')     # 定制allure报告用例描述
    @allure.severity(allure.severity_level.BLOCKER)     # 定制allure报告显示的的重要等级
    @pytest.mark.parametrize('Title, Body, expData', yaml_case_data('loginCaseData.yaml'))   # 数据驱动
    def test_login(self, Title, Body, expData):
        allure.dynamic.title(f'{Title}')   # 定制allure报告的用例标题
        allure.dynamic.description('用户登录接口')    # 定制allure报告的用例描述
        resp = Login().login(Body)
        self.assert_equal(resp['meta']['status'], expData['status'])
        self.assert_equal(resp['meta']['msg'], expData['msg'])

1.4config配置文件目录

存放host、用户名和密码、项目路径等全局配置文件

1.5datas测试数据目录

以yaml文件格式存放一些测试数据和测试过程中需要上传或卸载的一些文件

1.6log日子目录

存放测试执行过程中产生的一些日子文件

1.7report测试报告目录

temp-----存放allure报告生成的json文件

allure-report-----存放allure报告的html文件

1.8tool目录

存放yaml文件解析和定制日志器的方法

1.8.1yaml文件测试数据解析方法

"""
读取YAML测试用例数据
"""
import yaml
from configs.base_path import data_path


def yaml_case_data(fileName):
    dataList = []
    with open(f'{data_path}'+f'/{fileName}', 'r', encoding='utf8') as f:
        data = yaml.safe_load(f)
        for one in data:
            dataList.append((one['title'], one['body'], one['resp']))
    return dataList

1.8.2定制日志器

"""
日志输出
"""
import logging
import time

from configs.base_path import log_path


def logger(name=__name__):
    """
    :param name: __name__为模块名称
    :return: 返回日志对象实例
    """
    # 创建日志对象
    logObject = logging.getLogger(name)
    # 设置输出级别
    logObject.setLevel(logging.INFO)
    logTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    # 日志输出路径
    logPath = log_path + f"/test{logTime}.log"
    # 创建文件输出
    FH = logging.FileHandler(logPath)
    # 创建控制台输出
    SH = logging.StreamHandler()
    # 定制日志输出内容和格式
    FM = logging.Formatter(fmt="[%(asctime)s][%(levelname)s][%(filename)s-%(lineno)d]:%(message)s",
                           datefmt="%Y-%m-%d %H:%M:%S")
    # 日志器添加输出格式
    FH.setFormatter(FM)
    SH.setFormatter(FM)
    # 为日志对象添加日志输出器
    logObject.addHandler(FH)
    logObject.addHandler(SH)
    return logObject


log = logger()

1.9contest.py文件

conftest.py使用fixture夹具实现token传递、各模块的实例化(用例层调用业务类时不需要再实例化对象,可以实现一次实例化,多次使用,减少代码量)、解决接口数据依赖问题

"""
conftest.py运行夹具
"""
import pytest
from libs.login import Login
from configs.name_passwd import USER_PASSWD
from libs.upload import Upload
from libs.user import User


# ----------获取token----------
@pytest.fixture(scope='session')
def login_init():  # 获取token
    token = Login().login(USER_PASSWD, getToken=True)
    yield token


# ----------实例化用户管理模块--------
@pytest.fixture(scope='class')
def user_init(login_init):  # 实例化用户管理模块
    userObject = User(login_init)
    yield userObject  # 返回用户管理实例对象


# ----------添加用户,返回用户id----------
@pytest.fixture(scope='function')
def user_id(user_init):
    data = dict(username="jay", password="123456", email="yy@xx.com", mobile="12377778888")
    userID = user_init.send_post(data)['data']['id']
    yield userID
    user_init.send_delete(f'/{userID}', inURL=True)


# --------图片上传实例化---------
@pytest.fixture(scope='class')
def upload_init(login_init):  # 实例化用户管理模块
    uploadObject = Upload(login_init)
    yield uploadObject  # 返回用户管理实例对象

1.10pytest配置文件

[pytest]
addopts: -vs --alluredir=report/temp --clean-alluredir    # pytest执行命令参数,-v输出详细信息,-s控制台输出, allure设置目录,执行完后自动清理allure报告残留数据
marker:
    login: 登录模块用例      # 标记用例
    user: 用户管理模块用例      # 标记用例

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐