python自动化(五)接口自动化:4.接口自动化框架搭建实战
一.业务分析我们这里以企业微信的添加成员业务为例,来讲解我们的自动化测试框架。企业微信接口文档:https://work.weixin.qq.com/api/doc/90000/90135/90195二.框架搭建实战1.框架目录结构分析data:存放测试用例数据的目录。images:存放项目图片的目录。logs:存放日志文件的目录。my_config:存放配置文件的目录。my_tools:存放公共
·
一.业务分析
我们这里以企业微信的添加成员业务为例,来讲解我们的自动化测试框架。
企业微信接口文档:https://work.weixin.qq.com/api/doc/90000/90135/90195
二.框架搭建实战
1.框架目录结构分析
- data:存放测试用例数据的目录。
- images:存放项目图片的目录。
- logs:存放日志文件的目录。
- my_config:存放配置文件的目录。
- my_tools:存放公共方法代码的位置。
- page_obj:存放page类代码的目录。
- test_case:存放用例代码的位置
2.公共方法封装
(1)获取项目根路径方法封装
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os
def get_base_dir():
"""
获取项目根目录
:return:
"""
now_dir = os.getcwd()
while True:
now_dir_list = os.path.split(now_dir)
now_dir = now_dir_list[0]
if now_dir_list[1] == "xiongxiong_test_frame":
now_dir = os.path.join(now_dir_list[0], now_dir_list[1])
break
return os.path.join(now_dir,'api_frame')
if __name__ == "__main__":
print(get_base_dir())
(2)日志方法封装
#! /usr/bin/python
# -*- coding: utf-8 -*-
import logging
class GetLog:
"""
自定义logging类
方法:1.get_logger:获取一个Logger对象。
"""
def get_logger(self, name, level, fromt, path):
"""
获取Logger对象。
:param name: Logger名字。
:param level: Logger级别。
:param fromt: Logger日志输出级别。
:param path: 日志文件路径。
:return: Logger对象
"""
self.logger = logging.getLogger(name=name)
self.logger.setLevel(logging.DEBUG)
if not self.logger.hasHandlers():
# 给Logger添加一个FileHandler
file_handler = logging.FileHandler(filename=path,encoding='utf-8')
file_handler.setLevel(level=level)
file_handler.setFormatter(fmt=fromt)
self.logger.addHandler(file_handler)
# 给Logger添加一个FileHandler
stream_handler = logging.StreamHandler()
stream_handler.setLevel(level=level)
stream_handler.setFormatter(fmt=fromt)
self.logger.addHandler(stream_handler)
return self.logger
(3)当前时间串方法封装
#! /usr/bin/python
# -*- coding: utf-8 -*-
from datetime import datetime
def get_now_time():
"""
获取当前时间字符串
:return:
"""
now = datetime.now().strftime('%Y-%m-%d-%H%M%S')
return now
if __name__ == "__main__":
print(get_now_time())
3.配置文件的使用
#! /usr/bin/python
# -*- coding: utf-8 -*-
# create_time: 2021-02-22
import logging
import os
from api_frame.my_tools.get_dir import get_base_dir
## 目录配置
# 项目目录
BASEDIR = get_base_dir()
# 临时图片目录
IMAGESDIR = os.path.join(BASEDIR,"images")
# 测试数据目录
TESTDATA = os.path.join(BASEDIR,"data/contact_data")
## 日志配置
import os
from api_frame.my_tools.get_log import GetLog
from api_frame.my_tools.get_strtime import get_now_time
LOG_NAME = 'ROOT'
LOG_PATH = os.path.join(BASEDIR,f'logs/{get_now_time()}.log')
LOG_LEVEL = logging.INFO
LOG_FORMAT = logging.Formatter('%(asctime)s-%(levelname)s-%(message)s-%(filename)s-%(lineno)d-%(funcName)s')
# 实例化以后Logger对象
LOGGER = GetLog().get_logger(name=LOG_NAME, level=LOG_LEVEL, fromt=LOG_FORMAT, path=LOG_PATH)
4.pageobje类的封装
注意:我们本次虽然只测试添加成员接口,但该接口的用例对删除成员,添加部门,删除部门等接口有数据依赖,所以也需要将这些接口封装到page类中。
basepage基类封装
#! /usr/bin/python
# -*- coding: utf-8 -*-
# createtime: 2021-02-01
import requests
from requests import Session
class BasePage:
def __init__(self,corpid=None,corpsecret=None,session=None):
# 生成session
if session:
self.session = session
else:
if corpid is None:
my_corpid = 'wwb0963a3a379de433'
else:
my_corpid = corpid
if corpsecret is None:
my_corpsecret = 'X-G73KTHX9is69sJcNbv-T80SyqL86EyvFUOpm4MTsg'
else:
my_corpsecret = corpsecret
r = requests.get(url=f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={my_corpid}&corpsecret={my_corpsecret}')
token = r.json()['access_token']
self.session = Session()
# 将token封装到session
self.session.params['access_token'] = token
成员模块相关接口封装
#! /usr/bin/python
# -*- coding: utf-8 -*-
# createtime: 2021-02-01
import os
from typing import List
from api_frame.my_config.config import BASEDIR,LOGGER
from api_frame.page_obj.base_page import BasePage
class ContactPage(BasePage):
"""
通讯录管理相关接口封装
"""
def add_remenber(self,add_remenber:dict=None):
"""
添加成员接口封装
:param add_remenber: 添加成员接口请求数据
:return: 接口返回对象
"""
try:
# 获取请求数据
json_data = add_remenber
# 发送请求
r = self.session.post(url='https://qyapi.weixin.qq.com/cgi-bin/user/create',json=json_data)
LOGGER.info('Access to "add_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/create success')
return r
except Exception as e:
LOGGER.error('Access to "add_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/create failed')
raise e
def find_remenber(self,userid):
"""
查询成员接口封装
:param userid: 成员UserID。对应管理端的帐号,企业内必须唯一。不区分大小写,长度为1~64个字节
:return: 接口返回对象
"""
try:
params = {
"userid": userid
}
r = self.session.get(url='https://qyapi.weixin.qq.com/cgi-bin/user/get',params=params)
LOGGER.info('Access to "find_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/get success')
return r
except Exception as e:
LOGGER.error('Access to "find_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/get failed')
raise e
def delete_remenber(self,delete_remenber_data:dict):
"""
删除成员接口封装
:param delete_remenber_data: 成员UserID。对应管理端的帐号,企业内必须唯一。不区分大小写,长度为1~64个字节
:return: 接口返回对象
"""
try:
params = delete_remenber_data
r = self.session.get(url='https://qyapi.weixin.qq.com/cgi-bin/user/delete',params=params)
LOGGER.info('Access to "delete_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/delete success')
return r
except Exception as e:
LOGGER.error('Access to "delete_remenber" url https://qyapi.weixin.qq.com/cgi-bin/user/delete failed')
raise e
部门管理接口封装
#! /usr/bin/python
# -*- coding: utf-8
# create_time: 2021-02-24
from api_frame.my_config.config import LOGGER
from api_frame.page_obj.base_page import BasePage
class DepartmentPage(BasePage):
"""部门管理page类"""
def add_department(self,add_department:dict):
"""
添加部门接口封装
:param add_department: 添加部门请求参数
:return: 接口响应对象
"""
try:
# 生成请求数据
json_data = add_department
# 发送请求
r = self.session.post("https://qyapi.weixin.qq.com/cgi-bin/department/create",json=json_data)
LOGGER.info('Access to "add_department" url https://qyapi.weixin.qq.com/cgi-bin/department/create success')
return r
except Exception as e:
LOGGER.error('Access to "add_department" url https://qyapi.weixin.qq.com/cgi-bin/department/create failed')
raise e
def del_department(self,del_deparment:dict):
"""
删除部门接口封装
:param del_deparment: 删除部门请求参数
:return: 接口响应对象
"""
try:
# 生成请求数据
json_data = del_deparment
# 发送请求
id = del_deparment.get('id')
r = self.session.get(url=f"https://qyapi.weixin.qq.com/cgi-bin/department/delete?id={id}")
LOGGER.info(f'Access to "del_department" url https://qyapi.weixin.qq.com/cgi-bin/department/delete?id={id} success')
return r
except Exception as e:
LOGGER.error(
f'Access to "del_department" url https://qyapi.weixin.qq.com/cgi-bin/department/delete?id={id} failed')
raise e
素材管理接口封装
#! /usr/bin/python
# -*- coding: utf-8
# create_time: 2021-02-24
import os
from api_frame.page_obj.base_page import BasePage
from api_frame.my_config.config import BASEDIR,IMAGESDIR,LOGGER
class MaterialPage(BasePage):
"""素材管理page类"""
def up_image(self,filename:dict):
"""
上传图片
:return:
"""
try:
filename = filename.get('filename')
filedir = os.path.join(IMAGESDIR,filename)
with open(file=filedir,mode='rb') as f:
file = {"file": f}
r = self.session.post("https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=image",files=file)
LOGGER.info(
f'Access to "up_image" url https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=image success')
return r
except Exception as e:
LOGGER.error(
f'Access to "up_image" url https://qyapi.weixin.qq.com/cgi-bin/media/upload?type=image failed')
raise e
if __name__ == "__main__":
s = MaterialPage().up_image("my_wework.png")
print(s.json())
5.测试用例的编写
在page类封装完成后,我们便可以使用page类中的方法来编写测试用例。编写用例时需要注意用例数据的独立性,数据在用例中生成,且用例完成后将遗留数据清除。
(1)数据文件编写
# 成功userid以字母开头
- add_remenber:
userid: "ojbk0123_-@.001"
name: "ojbk001"
mobile: "13118170001"
department: [1]
expect:
errcode: 0
errmsg: "created"
# 成功userid以数字开头
- add_remenber:
userid: "77ojbk0123_-@.002"
name: "ojbk002"
mobile: "13118170002"
department: [1]
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,email,department。
- add_remenber:
userid: "ojbk0123_-@.003"
name: "ojbk003"
email: "1230001@qq.com"
department: [1]
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department。且关联多个部门
- add_remenber:
userid: "ojbk0123_-@.004"
name: "ojbk004"
mobile: "13118170004"
department: [1,2]
add_department:
name: "ojbk004"
parentid: 1
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,alias
- add_remenber:
userid: "ojbk0123_-@005"
name: "ojbk005"
mobile: "13118170005"
department: [1]
alias: "ojbk005"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,order。
- add_remenber:
userid: "ojbk0123_-@006"
name: "ojbk006"
mobile: "13118170006"
department: [1]
order: 1
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,position。
- add_remenber:
userid: "ojbk0123_-@007"
name: "ojbk007"
mobile: "13118170007"
department: [1]
position: "产品经理"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,gender。
- add_remenber:
userid: "ojbk0123_-@008"
name: "ojbk008"
mobile: "13118170008"
department: [1]
gender: 1
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,gender
- add_remenber:
userid: "ojbk0123_-@009"
name: "ojbk009"
mobile: "13118170009"
department: [1]
gender: 2
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,email。
- add_remenber:
userid: "ojbk0123_-@010"
name: "ojbk010"
mobile: "13118170010"
department: [1]
email: "123010@qq.com"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,telephone。
- add_remenber:
userid: "ojbk0123_-@011"
name: "ojbk011"
mobile: "13118170011"
department: [1]
telephone: "0519-000011"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,is_leader_in_dept。
- add_remenber:
userid: "ojbk0123_-@012"
name: "ojbk012"
mobile: "13118170012"
department: [1]
is_leader_in_dept: 0
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,is_leader_in_dept。
- add_remenber:
userid: "ojbk0123_-@.013"
name: "ojbk013"
mobile: "13118170013"
department: [1]
is_leader_in_dept: 1
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,avatar_mediaid。
- add_remenber:
userid: "ojbk0123_-@014"
name: "ojbk014"
mobile: "13118170014"
department: [1]
up_images:
filename: my_wework.png
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,enable。
- add_remenber:
userid: "ojbk0123_-@015"
name: "ojbk015"
mobile: "13118170015"
department: [1]
enable: 0
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,enable
- add_remenber:
userid: "ojbk0123_-@016"
name: "ojbk016"
mobile: "13118170016"
department: [1]
enable: 1
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,external_position。
- add_remenber:
userid: "ojbk0123_-@.017"
name: "ojbk017"
mobile: "13118170017"
department: [1]
external_position: "项目经理"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,external_position,positionv。
- add_remenber:
userid: "ojbk0123_-@.018"
name: "ojbk018"
mobile: "13118170018"
department: [1]
external_position: "项目经理"
position: "产品经理"
expect:
errcode: 0
errmsg: "created"
# 请求数据只传入正确的userid,name,mobile,department,address
- add_remenber:
userid: "ojbk0123_-@.019"
name: "ojbk019"
mobile: "13118170019"
department: [1]
address: "四川省南充市营山县"
expect:
errcode: 0
errmsg: "created"
# userid包含其他字符。
- add_remenber:
userid: "ojbk0123_-@.##020"
name: "ojbk020"
mobile: "13118170020"
department: [1]
expect:
errcode: 40003
# userid以特殊字符开头
- add_remenber:
userid: "@ojbk0123_-@.021"
name: "ojbk021"
mobile: "13118170021"
department: [1]
expect:
errcode: 40003
# userid为超长字符
- add_remenber:
userid: "@ojbk0123_-@.022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
name: "ojbk022"
mobile: "13118170022"
department: [1]
expect:
errcode: 40058
# userid为空
- add_remenber:
name: "ojbk023"
mobile: "13118170023"
department: [1]
expect:
errcode: 41009
# name为空
- add_remenber:
userid: "ojbk0123_-@.024"
mobile: "13118170024"
department: [1]
expect:
errcode: 60112
# mobile和email同时为空
- add_remenber:
userid: "ojbk0123_-@.025"
name: "ojbk025"
department: [1]
expect:
errcode: 60129
# department为空
- add_remenber:
userid: "ojbk0123_-@.026"
name: "ojbk026"
mobile: "13118170026"
expect:
errcode: 40066
# department为不存在的部门id
- add_remenber:
userid: "ojbk0123_-@.027"
name: "ojbk027"
mobile: "13118170027"
department: [5]
expect:
errcode: 40066
# mobile为错误的手机格式(13位)
- add_remenber:
userid: "ojbk0123_-@.029"
name: "ojbk029"
mobile: "1311812700029"
department: [1]
expect:
errcode: 0
# mobile为错误的手机格式(10位)
- add_remenber:
userid: "ojbk0123_-@.030"
name: "ojbk030"
mobile: "1311817030"
department: [1]
expect:
errcode: 60103
# email为错误的邮箱格式
- add_remenber:
userid: "ojbk0123_-@.031"
name: "ojbk031"
mobile: "13118170031"
department: [1]
email: "123000@"
expect:
errcode: 60105
# 重复的userid
- add_remenber:
userid: "ojbk0123_-@.032"
name: "ojbk032"
mobile: "13118170032"
department: [1]
re_add_remenber:
userid: "ojbk0123_-@.032"
name: "ojbk0321"
mobile: "13118170055"
department: [1]
expect:
errcode: 60102
# 重复的mobile
- add_remenber:
userid: "ojbk0123_-@.033"
name: "ojbk033"
mobile: "13118170033"
department: [1]
re_add_remenber:
userid: "ojbk0123_-@.0331"
name: "ojbk0331"
mobile: "13118170033"
department: [1]
expect:
errcode: 60104
# 重复的email
- add_remenber:
userid: "ojbk0123_-@.034"
name: "ojbk034"
mobile: "13118170034"
department: [1]
email: "1230034@qq.com"
re_add_remenber:
userid: "ojbk0123_-@.0341"
name: "ojbk0341"
mobile: "13118170088"
department: [1]
email: "1230034@qq.com"
expect:
errcode: 60106
(2)用例的编写
#! /usr/bin/python
# -*- coding: utf-8 -*-
# create_time: 2021-02-26
import os
import pytest
import yaml
from api_frame.page_obj.contact_page import ContactPage
from api_frame.my_config.config import TESTDATA,LOGGER
from api_frame.page_obj.department_page import DepartmentPage
from api_frame.page_obj.material_page import MaterialPage
class TestAddRmenber:
# 获取请求数据
data_path = os.path.join(TESTDATA, "add_remenber.yaml")
with open(file=data_path, mode='r', encoding='utf-8') as f:
data = yaml.safe_load(f)
def setup_class(self):
self.contact = ContactPage()
self.department = DepartmentPage(session=self.contact.session)
self.materia = MaterialPage(session=self.contact.session)
@pytest.fixture(params=data)
def get_data(self,request):
"""
自定义用例的前置后置方法
:param request:
:return:
"""
LOGGER.info('》》》》》》》START TO EXECUTION CASE 》》》》》》')
LOGGER.info('GENERATE TEST CASE DATA')
# 生成用例的依赖数据
add_department_data = request.param.get('add_department')
up_images_data = request.param.get('up_images')
re_add_remenber_data = request.param.get('re_add_remenber')
if add_department_data: # 是否需要临时生成部门
r = self.department.add_department(add_department_data)
department_id = r.json()['id']
assert r.json()['errcode'] == 0
if up_images_data: # 是否需要临时上传图片
r = self.materia.up_image(up_images_data)
avatar_mediaid = r.json().get('media_id')
assert r.json()['errcode'] == 0
request.param['add_remenber']['avatar_mediaid'] = avatar_mediaid
if re_add_remenber_data: # 是否需要创建两个用户
r = self.contact.add_remenber(re_add_remenber_data)
assert r.json()['errcode'] == 0
yield request.param
LOGGER.info('CLEAR TEST CASE DATA')
# 清理用例的依赖数据,及用例数据
if up_images_data: # 清理图片上传数据
self.avatar_mediaid = None
if re_add_remenber_data: # 清理多用户数据
re_del_remenber_data = {}
re_del_remenber_data['userid'] = re_add_remenber_data.get('userid')
r = self.contact.delete_remenber(re_del_remenber_data)
assert r.json()['errcode'] == 0
# 清理用例创建的用户
except_data = request.param.get('expect').get("errcode")
if except_data == 0:
del_remenber_data = {}
del_remenber_data['userid'] = request.param.get('add_remenber').get('userid')
r = self.contact.delete_remenber(del_remenber_data)
assert r.json()['errcode'] == 0
if add_department_data: # 清理department数据
del_department_data = {}
del_department_data['id'] = department_id
r = self.department.del_department(del_department_data)
assert r.json()['errcode'] == 0
LOGGER.error("》》》》》》》END TO EXECUTION CASE 》》》》》》")
# @pytest.mark.parametrize("data",data)
def test_addremenber(self,get_data):
"""添加成员接口测试用例"""
LOGGER.info('TEST ADD_REMENBER CASE')
# 添加成员接口测试
add_remenber_data = get_data.get('add_remenber')
r = self.contact.add_remenber(add_remenber_data)
# 断言
expect:dict = get_data.get('expect')
errcode = expect.get('errcode')
errmsg = expect.get('errmsg')
if errcode:
assert r.json()['errcode'] == errcode
if __name__ == "__main__":
pytest.main(['-vs','test_add_remenber.py'])
到这里我们的框架基本上就搭建起来了,后续如果有更多的用例可以继续在该框架中补充。
更多推荐
已为社区贡献1条内容
所有评论(0)