接口自动化项目实现思想

一:接口自动化实现思想

代码分层思想

测试脚本层:调用接口,按照响应数据,断言完成测试。
1.重点关注测试数据准备和断言
2.直接调用接口对象层发送请求

接口对象层:发送http请求,访问待测接口,返回响应数据。
1.根据接口api文档封装
2.重点关注如何调用接口
3.请求参数从测试脚本层传递
4.接口响应结果返回给脚本层

在这里插入图片描述
将变化的当做参数传入,不变的部分封装成类或者方法。

二、接口实现细节

1.登录接口封装前后

接口封装实现

import requests

class TpshopLoginApi(object):  
    # 获取验证码
    @classmethod
    def get_verify(cls,session):
        session.get(url='http://wwwww')
    
    # 登录
    @classmethod
    def login(cls,session,login_data):
        resp=session.post(url='http://www',data=login_data)
        return resp 
    
if __name__ == '__main__':
    # 测试封装的接口对象层,功能是否正确
    session=requests.Session()
    TpshopLoginApi.get_verify(session)
    login_data={"username":"wwww","password":"3434"}
    resp=TpshopLoginApi.login(session,login_data)
    print("登录结果:",resp.json())

接口调用测试

from py_03_thshopApi import TpshopLoginApi
import requests

class TestTPShopLogin(object):
    # 定义 测试方法-登录成功
    def test01_login_success(self):
        session=requests.Session()
        # 发送验证码
        TpshopLoginApi.get_verify(session)
        # 发送登录
        login_data={"username":"22","password":"8888"}
        resp=TpshopLoginApi.login(session,login_data)
        # 打印响应结果
        print("登录成功:",resp.json())
        
        # 添加断言
        assert 200==resp.status_code
        assert 1==resp.json().get("status")
        assert "登录成功" in resp.json().get("msg")
        
    # 密码错误
    def test02_pwd_err(self):
        session = requests.Session()
        # 发送验证码
        TpshopLoginApi.get_verify(session)
        # 发送登录
        login_data = {"username": "22", "password": "8888"}
        resp = TpshopLoginApi.login(session, login_data)
        # 打印响应结果
        print("登录失败:", resp.json())

        # 添加断言
        assert 200 == resp.status_code
        assert -2 == resp.json().get("status")
        assert "登录失败" in resp.json().get("msg")
    # 验证码错误
    def test03_verify_err(self):
        session = requests.Session()
        # 发送验证码
        TpshopLoginApi.get_verify(session)
        # 发送登录
        login_data = {"username": "22", "password": "8888"}
        resp = TpshopLoginApi.login(session, login_data)
        # 打印响应结果
        print("登录失败:", resp.json())

        # 添加断言
        assert 200 == resp.status_code
        assert 0 == resp.json().get("status")
        assert "验证码错误" in resp.json().get("msg")
    

接口调用,优化后:(对公用的方法进行抽离,封装)

from py_03_thshopApi import TpshopLoginApi
import requests

class TestTPShopLogin(object):
    # 类属性调用 可以用类名、实例、self、cls,均可引用
    session=None
    def setup(self):
        session=requests.Session()
        # 发送验证码
        TpshopLoginApi.get_verify(self.session)

    # 定义 测试方法-登录成功
    def test01_login_success(self):
        # 发送登录
        login_data={"username":"22","password":"8888"}
        resp=TpshopLoginApi.login(self.session,login_data)
        # 打印响应结果
        print("登录成功:",resp.json())

        # 添加断言
        assert 200==resp.status_code
        assert 1==resp.json().get("status")
        assert "登录成功" in resp.json().get("msg")

    # 密码错误
    def test02_pwd_err(self):
        # 发送登录
        login_data = {"username": "22", "password": "8888"}
        resp = TpshopLoginApi.login(self.session, login_data)
        # 打印响应结果
        print("登录失败:", resp.json())

        # 添加断言
        assert 200 == resp.status_code
        assert -2 == resp.json().get("status")
        assert "登录失败" in resp.json().get("msg")
    # 验证码错误
    def test03_verify_err(self):


        # 发送登录
        login_data = {"username": "22", "password": "8888"}
        resp = TpshopLoginApi.login(self.session, login_data)
        # 打印响应结果
        print("登录失败:", resp.json())

        # 添加断言
        assert 200 == resp.status_code
        assert 0 == resp.json().get("status")
        assert "验证码错误" in resp.json().get("msg")


setup():每个方法运行前都会运行一次
setup_class():每个类运行之前都会运行一次

2.定义项目目录结构

api:定义封装被测接口(接口对象层 py文件夹)
scripts:定义测试用例脚本(测试脚本层 py文件夹)
data:存放测试数据文件(测试数据文件 文件)
report:存放生成的测试报告(文件)
common:存放通用工具类
config.py:配置的全局变量
pytest.ini:pytest配置
在这里插入图片描述

3.pytest.ini

定义pytest.ini文件
运行的时候,可以直接在pycharm终端运行,使用命令pytest

[pytest]
addopts = -s --html=./report/ihrmReport.html --self-contained-html
testpaths = ./scripts
python_files = test*.py
python_classes = Test*
python_functions = test*
4.断言

断言 定义为一个通用的方法(common目录)

def common_assert(resp, status_code, success, code, message):
    assert status_code == resp.status_code
    assert success is resp.json().get("success")
    assert code == resp.json().get("code")
    assert message in resp.json().get("message")
5.参数化

数据参数化:
创建一个新的json文件,将接口用例需要传入的参数,使用json格式列举,在调用的时候,读取json文件。
在这里插入图片描述
读取文件 parameterize

1.参数化的核心:数据驱动->用数据驱动测试用例的执行(几条数据,用例执行多少次),针对一个接口,只写一个测试方法,用一份测试数据文件,管理各个用例的测试数据。

读取json文件的时候,建议使用绝对路径:
1.在config.py文件中,添加全局变量,获取项目目录BASE_DIR=os.path.dirname( _ file _ )
2.拼接json文件的绝对路径 BASE_DIR+“/data/login_data.json”
3.使用绝对路径,传入json文件读取函数 read_json_data

import os

# 定义全局变量,获取项目路径
BASE_DIR = os.path.dirname(__file__)
print(BASE_DIR)
import pytest
from api.ihrm_login_api import LoginApi
from common.assert_tools import common_assert
from common.logging_use import init_log_config
from common.read_json_file import read_json_data
from config import BASE_DIR


class TestLoginParams(object):
    # 读取json文件,获取[(),(),()]格式数据
    data = read_json_data(BASE_DIR + "/data/login_data.json")

    @pytest.mark.parametrize("desc, req_data, status_code, success, code, message", data)
    # 定义 通用测试方法 - 测试ihrm登录接口
    def test_login(self, desc, req_data, status_code, success, code, message):
        # 调用 自己封装的 api, 获取响应结果
        resp = LoginApi.login(req_data)
        # 打印查看
        # print(desc, ":", resp.json())
        logging.info(f"{desc} : {resp.json()}")
        # 断言
        common_assert(resp, status_code, success, code, message)
6.注意

(1)解决数据反复修改问题

  1. 数据使用一次后不能再次使用,比如手机号、用户id,在测试前(setup),要保证数据库里没有该数据,所以可执行delete SQL语句,将其删除!
  2. 在测试 添加接口结束之后(teardown),删除添加接口测试时,使用的手机号或者用户id。
  3. sql语句 手机号 固定常量 可重复使用!将手机号设置 全局变量。
# 定义全局变量,测试用的手机号
TEL = "18648390001"
from config import TEL

    def setup(self):
        del_sql = f"delete from bs_user where mobile='{TEL}';"
        DBTools.db_uid(del_sql)

    def teardown(self):
        del_sql = f"delete from bs_user where mobile='{TEL}';"
        DBTools.db_uid(del_sql)
# 定义测试方法 - 添加成功
    def test01_add_ok(self):
        # 调用自己封装的 api,发送 添加员工请求
        req_data = {
            "username": "user87655430",
            "mobile": TEL,#定义TEL本身就是一个字符串,不用使用格式占位符
            "workNumber": "9527890aa"
        }
        resp = EmpApi.add_emp(self.req_header, req_data)
        print("必选-添加成功:", resp.json())
        # 断言
        common_assert(resp, 200, True, 10000, "操作成功")

(2)用例自动化中,存在部分用例无法执行(手机号重复):
为了解决手机号重复问题,我们将手机号设置为全局变量,如果要执行手机号重复的自动化用例,和我们设置的全局变量冲突,这种情况,可以手动补充该种场景去执行!

7.请求头动态获取

请求头需要动态获取,每次调用接口之前,都需要获取新的请求头,所以 抽出来写成一个方法,在类执行之前调用一次(setup_class)

"""
定义 函数,获取登录成功令牌,组织请求头
"""
from api.login_api import LoginApi


def get_header():
    req_data = {"mobile": "13800000002", "password": "123456"}
    resp = LoginApi.login(req_data)
    header = {"Authorization": resp.json().get("data")}
    return header


if __name__ == '__main__':
    ret = get_header()
    print(ret)

# 定义测试类 - 实现参数化
class TestAddEmpParams(object):
    req_header = None

    def setup_class(self):
        self.req_header = get_header()
8.生成测试报告
[pytest]
addopts = -s --html=./report/Report.html --self-contained-html
testpaths = ./scripts
python_files = test*.py
python_classes = Test*
python_functions = test*

addopts:pytest执行时携带的参数 --html=./report/Report.html 报告存放路径(./代表当前ini文件的同级目录)
参数–self-containted-html:测试用例执行过程中会生成一些中间缓存文件,加该参数 不需要生成该中间文件

9.日志收集

(1).日志:记录系统运行过程中产生的信息,对一个事件的记录,也成log。
有哪些信息需要记录:

  • 脚本运行过程中某个重要变量的值
  • 方法的输入参数和返回结果
  • 异常信息

(2).日志级别:
logging.DEBUG:调试级别,级别高
logging.info:信息级别,次高
logging.warning:警告级别 中
logging.error:错误级别,低
logging.critical:严重错误级别 极低

(3).定义自动化脚本运行的日志级别:一般调试或者信息级别用的较多(设置比设置日志级别低的日志才会打印)

import logging.handlers
import logging
from config import BASE_DIR


def init_log_config(filename, when='midnight', interval=1, backup_count=7):
    """
    功能:初始化日志配置函数
    :param filename: 日志文件名
    :param when: 设定日志切分的间隔时间单位,midnight,代表午夜
    :param interval: 间隔时间单位的个数,指等待多少个 when 后继续进行日志记录
    :param backup_count: 保留日志文件的个数,7代表保留近七天
    :return:
    """
    # 1. 创建日志器对象
    logger = logging.getLogger()

    # 2. 设置日志打印级别
    logger.setLevel(logging.DEBUG)
    # logging.DEBUG 调试级别
    # logging.INFO 信息级别
    # logging.WARNING 警告级别
    # logging.ERROR 错误级别
    # logging.CRITICAL 严重错误级别

    # 3. 创建处理器对象
    # 控制台对象
    st = logging.StreamHandler()
    # 日志文件对象
    fh = logging.handlers.TimedRotatingFileHandler(filename,
                                                   when=when,
                                                   interval=interval,
                                                   backupCount=backup_count,
                                                   encoding='utf-8')

    # 4. 日志信息格式
    fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s"
    formatter = logging.Formatter(fmt)

    # 5. 给处理器设置日志信息格式
    st.setFormatter(formatter)
    fh.setFormatter(formatter)

    # 6. 给日志器添加处理器
    logger.addHandler(st)
    logger.addHandler(fh)


if __name__ == '__main__':
    # 初始化日志
    init_log_config(BASE_DIR + '/log/sh27.log', interval=3, backup_count=5)

    # 打印输出日志信息
    logging.debug('我是一个调试级别的日志')
    logging.info("AAA BBB CCC")
    logging.error("xxxx 错误。。")
class TestLoginParams(object):
    init_log_config(BASE_DIR + '/log/sh27.log', interval=3, backup_count=5)

三、完整的脚本实现

api目录:

import requests

# 定义 员工管理 类
class EmpApi(object):
    # 定义 添加员工 方法
    @classmethod
    def add_emp(cls, header, req_data):
        resp = requests.post(url="http://ihrm-test.itheima.net/api/sys/user",
                             headers=header, json=req_data)
        return resp

    # 定义 查询员工 方法
    @classmethod
    def query_emp(cls, emp_id, header):
        resp = requests.get(url="http://ihrm-test.itheima.net/api/sys/user/"+emp_id, headers=header)
        return resp

    # 定义 修改员工 方法
    @classmethod
    def modify_emp(cls, emp_id, header, req_data):
        resp = requests.put(url="http://ihrm-test.itheima.net/api/sys/user/"+emp_id,
                            headers=header, json=req_data)
        return resp

    # 定义 删除员工 方法
    @classmethod
    def del_emp(cls, emp_id, header):
        return requests.delete(url="http://ihrm-test.itheima.net/api/sys/user/"+emp_id, headers=header)


if __name__ == '__main__':
    req_header = {"Authorization": "ca0da927-ae56-4902-b8ce-78ab8c8b55ad"}
    json = {
        "username": "user87655430",
        "mobile": "13947874780",
        "workNumber": "9527890aa"
    }
    response = EmpApi.add_emp(req_header, json)
    print("添加员工结果:", response.json())

    response = EmpApi.query_emp("1494919461403222016", req_header)
    print("查询员工结果:", response.json())

    modify_data = {"username": "放大镜考虑"}
    response = EmpApi.modify_emp("1494919461403222016", req_header, modify_data)
    print("修改员工结果:", response.json())

    response = EmpApi.del_emp("1494919461403222016", req_header)
    print("删除员工结果:", response.json())

scripts目录:
common目录:
data目录:
report目录:
pytest.ini:

[pytest]
addopts = -s --html=./report/ihrmReport.html --self-contained-html
testpaths = ./scripts
python_files = test*.py
python_classes = Test*
python_functions = test*

config.py:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小艾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值