金融项目实战 05|Python实现接口自动化——登录接口

目录

一、代码实现自动化理论及流程

二、脚本实现的理论和准备工作

1、抽取功能转为自动化用例

2、搭建环境(测试工具)

3、搭建目录结构

三、登录接口脚本实现

1、代码编写

1️⃣api目录

2️⃣script目录

2、断言

3、参数化

1️⃣编写数据存储文件:json文件

2️⃣编写读取数据工具:read_json()

3️⃣参数化引用:parameterize


一、代码实现自动化理论及流程

🔴代码编写脚本和工具实现脚本区别是什么?

  • 代码:
    • 优点:代码灵活方便
    • 缺点:学习成本高
  • 工具:
    • 优点:易上手
    • 缺点:灵活度低,有局限性。
  • 总结:
    • 功能脚本:工具
    • 自动化脚本:代码

🔴代码接口自动化怎么做的?

  • 第一步:(概述)python+request+unittest;
  • 第二步:(具体描述)封装、调用、数据驱动、日志、报告;
  • 第三步:(举例)api\scripts\data\log\report\until\...;

二、脚本实现的理论和准备工作

使用代码编写自动化脚本的流程:

  • 1、抽取功能用例转为自动化⽤例。
  • 2、搭建环境(测试工具相关的)
  • 3、搭建目录结构
  • 4、编写脚本
  • 5、执行脚本
  • 6、配置持续集成

1、抽取功能转为自动化用例

去掉了有bug的用例、以及"请求后台投资响应失败(密码为空)"的用例(改用例需要借钱和投资双方私下协商密码)

2、搭建环境(测试工具)

①python、pycharm、requests、pymysql、parametrize

②jenkins、jdk

提示:由于编写的自动化脚本,而自动化脚本编写之前功能已测试完毕,所以不需要在单独搭建项目环境。

3、搭建目录结构

三、登录接口脚本实现

1、代码编写

1️⃣api目录

把需要测的接口放在该目录
用到五个url,所以是5个接口,也需要在注册登录模块写五个方法

url设置成私有变量,只能在该类内部调用。

此处这样做只是因为url实际上只会在该登陆注册模块内部使用,外面没必须用到,设置私有,外部调用方法的时候。看着干净

python 复制代码
from config import HOST

class ApiRegisterLogin:
    # 有几个接口就封装几个方法
    #初始化
    def __init__(self, session):
        # 获取session对象
        self.session = session
        # 图片url
        # 图片验证码url
        self.__url_img_code = HOST + "/common/public/verifycode1/{}"
        # 短信验证码url
        self.__url_phone_code = HOST + "/member/public/sendSms"
        # 注册Lr1
        self.__url_register = HOST + "/member/public/reg"
        # 登录url
        self.__url_login = HOST + "/member/public/login"
        # 登录状态url
        self.__url_login_status = HOST + "/member/public/islogin"


    # url
    # 1、获取图⽚验证码接⼝ 封装
    def api_img_code(self,random):
        return self.session.get(url=self.__url_img_code.format(random))

    # 2、获取短信验证码接⼝ 封装
    def api_phone_code(self,phone,imgVerifyCode):
        data = {
            "phone": phone,
            "imgVerifyCode": imgVerifyCode,
            "type": "reg"
        }
        return self.session.post(url=self.__url_phone_code,data=data)

    # 3、注册接⼝ 封装
    def api_register(self,phone,password,verifycode,phone_code):
        data = {
            "phone": phone,
            "password": password,
            "verifycode": verifycode,
            "phone_code": phone_code,
            "dy_server": "on",
            "invite_phone": ""
        }
        return self.session.post(url=self.__url_register,data=data)

    # 4、登录接⼝ 封装
    def api_login(self,keywords,password):
        data = {
            "keywords": keywords,
            "password": password
        }
        return self.session.post(url=self.__url_login, data=data)

    # 5、查询登录状态接⼝ 封装
    def api_login_status(self):
        return self.session.post(url=self.__url_login_status)
2️⃣script目录

调用封装的接口,开展测试工作

下面测试用例的内容目前只是测试一下api文件中封装的接口能不能用,后面还要改。

python 复制代码
import unittest

import requests

from api.api_register_login import ApiRegisterLogin


class TestRegisterLogin(unittest.TestCase):
    # 初始化
    def setUp(self) -> None:
        # 获取session对象
        self.session =requests.Session()
        # 获取ApiRegisterLogin实例
        self.reg = ApiRegisterLogin(self.session)
    # 结束
    def tearDown(self) -> None:
        # 关闭session对象
        self.session.close()

    #1、获取图片验证码接口 测试
    def test01_img_code(self):
        # 调用图片验证码接口
        r = self.reg.api_img_code(234)
        # 查看响应状态码
        print(r.status_code)

    #2、获取短信验证码接口 测试
    def test02_phone_code(self,phone=17612341111,imgVerifyCode=8888):
        # 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie
        # 调用接口后session会自动记录cookie
        self.reg.api_img_code(234)
        # 2、调用短信验证码接口
        r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)
        # 3、查看响应结果
        print(r.json())

    #3、注册接口 测试
    def test03_register(self,phone=17612341111,imgVerifyCode=8888,password="win56",phone_code=666666):
        # 1、图片验证码接口
        self.reg.api_img_code(234)
        # 2、短信验证码接口
        self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
        # 3、注册接口
        r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)
        # 4、查看结果
        print(r.json())

    #4、登录接口 测试
    def test04_login(self,keywords=17612341111,password="win56"):
        # 1、调用登录
        r = self.reg.api_login(keywords=keywords,password=password)
        # 2、查看结果
        print(r.json())

    #5、查询登录状态接口 测试
    def test05_login_status(self):
        # 调用登录擦口
        self.reg.api_login(keywords=17612341111, password="win56")
        # 调用查询登录状态接口
        r = self.reg.api_login_status()
        # 看结果
        print(r.json())

2、断言

说明:判断程序执⾏实际结果是否符合预期结果

示例

实际需要将api_register_login.py中的每个测试用例都做异常处理,下面只是以查询登录接口中的异常捕获为例。

中的完整代码后续补充。

python 复制代码
try:
    # 调⽤登录接⼝
    self.reg.api_login(keywords="13600001111", password="test123")
    # 调⽤查询登录状态接⼝
    r = self.reg.api_login_status()
    # 看结果
    self.assertIn(expect_text, r.text)
except Exception as e:
    # ⽇志
    print(e)
    # 抛异常
    raise    
    # 提示:捕获异常的⽬的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常

【提示】:捕获异常的目的是为了将错误信息记录下来,捕获信息完成后,必须抛出异常

3、参数化

步骤

  • 1、编写数据存储⽂件 json
  • 2、编写读取⼯具⽅法 read_json()
  • 3、使⽤参数化组件进⾏引⽤ parametrize
1️⃣编写数据存储文件:json文件

心得:

1、根据模块来新建json文件(1个模块1个json⽂件)

2、最外侧使用{},模块下几个接口,编写几个key,值为列表

3、列表值中,有几组数据,就写几个{}

4、每组数据{}中,组成格式:说明+参数+预期结果

python 复制代码
{
  "img_code": [
    {
      "desc": "获取图片验证码成功(随机小数)",
      "random": 0.123,
      "expect_code": 200
    },
    {
      "desc": "获取图片验证码成功(随机整数)",
      "random": 123,
      "expect_code": 200
    },
    {
      "desc": "获取图片验证码失败(随机数为空)",
      "random": "",
      "expect_code": 404
    },
    {
      "desc": "获取图片验证码失败(随机数为字符串)",
      "random": "123hello",
      "expect_code": 400
    }
  ],
  "phone_code": [
    {
      "desc": "获取短信验证码成功",
      "phone": "13600001111",
      "imgVerifyCode": 8888,
      "expect_text": "发送成功"
    },
    {
      "desc": "获取短信验证码成功",
      "phone": "13600001111",
      "imgVerifyCode": 8889,
      "expect_text": "验证码错误"
    }
  ],
  "register": [
    {
      "desc": "注册成功(必填参数)",
      "phone": 13600001111,
      "password": "test123",
      "verifycode": 8888,
      "phone_code": 666666,
      "expect_text": "注册成功"
    },
    {
      "desc": "注册失败(图片验证码错误)",
      "phone": 13600001112,
      "password": "test123",
      "verifycode": 8889,
      "phone_code": 666666,
      "expect_text": "验证码错误"
    },
    {
      "desc": "注册失败(短信验证码错误)",
      "phone": 13600001112,
      "password": "test123",
      "verifycode": 8888,
      "phone_code": 666667,
      "expect_text": "验证码错误"
    },
    {
      "desc": "注册失败(手机号已存在)",
      "phone": 13600001111,
      "password": "test123",
      "verifycode": 8888,
      "phone_code": 666666,
      "expect_text": "已存在"
    }
  ],
  "login": [
    {
      "desc": "登录成功",
      "keywords": 13600001111,
      "password": "test123",
      "expect_text": "登录成功"
    },
    {
      "desc": "登录失败(密码为空)",
      "keywords": 13600001111,
      "password": "",
      "expect_text": "不能为空"
    },
    {
      "desc": "登录失败(解锁)",
      "keywords": 13600001111,
      "password": "error123",
      "expect_text": "登录成功"
    }
  ],
  "login_status": [
    {
      "desc": "查询登录状态(已登录)",
      "status": "已登录",
      "expect_text": "OK"
    },
    {
      "desc": "查询登录状态(已登录)",
      "status": "未登录",
      "expect_text": "未登"
    }
  ]
}
2️⃣编写读取数据工具:read_json()
python 复制代码
import json
import os

from config import DIR_PATH


def read_json(filename,key):
    # 拼接读取文件的完整路径
    # os.sep是动态获取/ \
    filepath = DIR_PATH + os.sep + "data" + os.sep +filename
    arr = []
    with open(filepath,"r",encoding="utf-8") as f:
        for data in json.load(f).get(key):
            arr.append(list(data.values())[1:])
    return arr
        
if __name__ == '__main__':
    # 测试一下能不能读取到数据
    print(read_json("register_login.json","img_code")) 

    # 读取的数据为:[[0.123, 200], [123, 200], ['', 404], ['123hello', 400]]
3️⃣参数化引用:parameterize

难点1:错误次数锁定

难点2: 查询登录状态,不同结果。

【注意】由于parameterized的自身bug,运行测试用例必须是点击到测试用例所在的类名右键运行。如果想单独运行某个接口用例,则把其他接口代码先注释掉。

python 复制代码
import unittest
from time import sleep

import requests

from api.api_register_login import ApiRegisterLogin

from parameterized import parameterized

from util import read_json


class TestRegisterLogin(unittest.TestCase):
    # 初始化
    def setUp(self) -> None:
        # 获取session对象
        self.session =requests.Session()
            # 获取ApiRegisterLogin实例
        self.reg = ApiRegisterLogin(self.session)


    # 结束
    def tearDown(self) -> None:
        # 关闭session对象
        self.session.close()

    #1、获取图片验证码接口 测试
    @parameterized.expand(read_json("register_login.json","img_code"))
    def test01_img_code(self,random,expect_code):
        try:
            # 调用图片验证码接口
            r = self.reg.api_img_code(random)
            # 查看响应状态码
            # print(r.status_code)
            self.assertEqual(expect_code,r.status_code)
        except Exception as err:
            # 日志
            print(err)
            # 抛异常
            raise

    #2、获取短信验证码接口 测试
    @parameterized.expand(read_json("register_login.json", "phone_code"))
    def test02_phone_code(self,phone,imgVerifyCode,expec_text):
        try:
            # 1、调用获取图片验证码接口 -- 目的:让session对象记录cookie
            # 调用接口后session会自动记录cookie
            self.reg.api_img_code(234)
            # 2、调用短信验证码接口
            r = self.reg.api_phone_code(phone=phone,imgVerifyCode=imgVerifyCode)
            # 3、查看响应结果
            # print(r.json())
            self.assertIn(expec_text,r.text) # 使用text提取结果是更方便,json还要根据键找值
        except Exception as err:
            # 日志
            print(err)
            # 抛异常
            raise

    #3、注册接口 测试
    @parameterized.expand(read_json("register_login.json", "register"))
    def test03_register(self,phone,password,imgVerifyCode,phone_code,expec_text):
        try:
            # 1、图片验证码接口
            self.reg.api_img_code(234)
            # 2、短信验证码接口
            self.reg.api_phone_code(phone=phone, imgVerifyCode=imgVerifyCode)
            # 3、注册接口
            r = self.reg.api_register(phone=phone,password=password,verifycode=imgVerifyCode,phone_code=phone_code)
            # 4、查看结果
            # print(r.json())
            self.assertIn(expec_text,r.text)
        except Exception as err:
            # 日志
            print(err)
            # 抛异常
            raise

    #4、登录接口 测试
    @parameterized.expand(read_json("register_login.json", "login"))
    def test04_login(self,keywords,password,expec_text):
        try:
            i = 0
            r = None
            if "error" in password:
                while i <3:
                    r=self.reg.api_login(keywords,password)
                    i+=1
                # 锁定断言
                print("账号密码输错3次,账号锁定:",r.text)
                self.assertIn("锁定",r.text)
                # 暂停60秒
                sleep(60)
                r = self.reg.api_login(keywords=17612341111, password="win56")
                self.assertIn(expec_text,r.text)


            else:
                # 1、调用登录
                r = self.reg.api_login(keywords,password)
                # 2、查看结果
                # print(r.json())
                self.assertIn(expec_text, r.text)
        except Exception as err:
            # 日志
            print(err)
            # 抛异常
            raise

    #5、查询登录状态接口 测试
    @parameterized.expand(read_json("register_login.json", "login_status"))
    def test05_login_status(self,status,expec_text):
        try:
            if status == "已登录":
                # 调用登录擦口
                self.reg.api_login(keywords=17612341111, password="win56")
            # 调用查询登录状态接口
            r = self.reg.api_login_status()
            # 看结果
            # print(r.json())
            self.assertIn(expec_text, r.text)
        except Exception as err:
            # 日志
            print(err)
            # 抛异常
            raise

【总结】目前为止已经写的文件,文件内容上面均给出了代码

相关推荐
草莓熊Lotso1 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
历程里程碑1 小时前
Linux22 文件系统
linux·运维·c语言·开发语言·数据结构·c++·算法
七夜zippoe9 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
Fcy64810 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满10 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠11 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey90311 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
珠海西格电力科技12 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
释怀不想释怀12 小时前
Linux环境变量
linux·运维·服务器
zzzsde12 小时前
【Linux】进程(4):进程优先级&&调度队列
linux·运维·服务器