API 自动化框架
API 自动化框架
个人认为接口自动化测试使用python语言编写更加简单,但所有接口自动化项目代码的思维都是一样的
1.项目包结构
1.case:存放用例数据的包,将所有用例数据以配置文件形式传入
2.core:核心包
1)config.py:封装ConfigParser解析获取配置文件数据的方法
python的内置模块ConfigParser:不太了解的可以百度
2)log.py:封装log的模块
3)request.py:封装接口测试的方法
4)mysql.py:封装连接数据库的方法
3.function:功能包,封装执行用例的方法,以及生成测试报告的方法
生成测试报告的原理:使用file生成.md文件,使用pip install mkdocs安装mkdocs,本地服务器的话端口默认为8000
4.report:存放所有生成的测试报告
5.constant.py:存放所有全局变量的模块
6.run.py:运行测试用例,以及生成测试报告的模块
2.核心代码
config.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 基础包:配置服务 import ConfigParser
import core.log as log config = ConfigParser.ConfigParser()
logging = log.get_logger() def get_config(filename):
"""
获取文件配置
:param filename: 配置文件名
:return: None
"""
global config
try:
config.read(filename)
return True
except Exception, e:
logging.error("读取配置失败 %s" % e) def get_data(title, key):
"""
参数配置
:param title: 配置文件的头信息
:param key: 配置文件的key值
:return: 配置文件的value
"""
try:
value = config.get(title, key)
type(value)
return value
except Exception, e:
logging.error("获取配置文件参数失败 %s" % e) def get_title_list():
"""
获取所有title
:return: title list
"""
try:
title = config.sections()
return str(title).decode("string_escape")
# return '\n'.join(title)
except Exception, e:
logging.error("获取title信息失败 %s", e)
mysql.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# author: zhizhi
# 基础包: MySQL import pymysql.cursors
import core.log as log logging = log.get_logger()
conn = None def connect(host, user, password, db, charset='utf8'):
"""
链接Mysql
:param host: 地址
:param user: 用户
:param password: 密码
:param db: 数据库名
:param charset: 数据类型
:return: 链接
"""
global conn
if conn == None:
conn = pymysql.connect(host=host,
user=user,
password=password,
db=db,
charset=charset,
cursorclass=pymysql.cursors.DictCursor)
return conn def execute(sql):
"""
执行SQL
:param sql: 执行的SQL
:return: 影响行数
"""
global conn
try:
with conn.cursor() as cursor:
res = cursor.execute(sql)
conn.commit()
# 这里一定要写commit 不然提交的sql 都会被事务回滚
return res
except Exception, e:
logging.error("sql is empty or error %s" % e) def close():
"""
关闭MySQL连接
:return: None
"""
global conn
conn.close()
request.py
#!/usr/bin/python
#-*- coding: UTF-8 -*-
# 基础包:接口测试的封装 import requests
import core.log as log
import json logging = log.get_logger() def change_type(value):
"""
对dict类型进行中文识别
:param value: 传的数据值
:return: 转码后的值
"""
try:
if isinstance(eval(value), str):
return value
if isinstance(eval(value), dict):
result = eval(json.dumps(value))
return result
except Exception, e:
logging.error("类型问题 %s", e) def api(method, url, data ,headers):
"""
自定义一个接口测试的方法
:param method: 请求类型
:param url: 地址
:param data: 数据
:param headers: 请求头
:return: success(str)
"""
global results
try:
if method == ("post" or "POST"):
results = requests.post(url, data, headers=headers,cookies=cookie)
if method == ("get" or "GET"):
results = requests.get(url, data, headers=headers,cookies=cookie) response = results.json()
success = response.get("success")
return success
except Exception, e:
logging.error("service is error", e) def set_cookieApi(method, url, data ,headers):
"""
自定义一个登录接口测试的方法
:param method: 请求类型
:param url: 地址
:param data: 数据
:param headers: 请求头
:return: success(bool)
"""
global cookie
try:
if method == ("post" or "POST"):
results = requests.post(url, data, headers=headers)
if method == ("get" or "GET"):
results = requests.get(url, data, headers=headers)
response = results.json()
success = str(response.get("success"))
cookie = requests.utils.dict_from_cookiejar(results.cookies)
return success
except Exception, e:
logging.info("LoginApi请求失败", e)
func.py: 可以通过接口返回数据与自己写的sql查询的数据进行对比,判断用例是否通过,所以提供了mysql通用模块
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 业务包:通用函数 import core.mysql as mysql
import core.log as log
import core.request as request
import core.config as conf
import constants as cs
import os logging = log.get_logger() class ApiTest:
"""接口测试业务类""" def __init__(self):
pass def prepare_data(self, host, user, password, db, sql):
"""
数据准备,添加测试数据
:param host: 服务地址
:param user: 用户
:param password: 密码
:param db: 数据库名
:param sql: 执行的SQL
:return:
"""
mysql.connect(host, user, password, db)
res = mysql.execute(sql)
mysql.close()
logging.info("Run sql: the row number affected is %s" % res)
return res def get_prepare_sql(self, filename, key):
"""
获取预备执行的SQL
:param title: 配置文件头信息
:param key: 配置文件值
:return: Value
"""
try:
conf.get_config(filename)
value = conf.get_data(title=cs.TITLE, key=key)
return value
except Exception, e:
logging.error("获取用例参数值失败 %s" % e) def new_report_menu(self, filename):
"""
这个方法主要是通过写入文件的方法,先打开cs.YML_REPORT也就是
mkdocs.yml文件,判断文件中是否存在当前写入的内容。
:param filename: 测试用例文件
:return: 测试报告内容
"""
try:
result = os.path.exists(cs.REPORT_PATH)
if result == True:
conf.get_config(filename)
reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
report_name = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.R_NAME))
file = open(cs.YML_REPORT, 'r')
list_con = file.readlines()
content = str(list_con).decode("string_escape")
fileContent = "- %s"
row = "\n"
_content = fileContent % (reportName + cs.NOW)
con = row + _content if _content not in content:
f = open(cs.YML_REPORT, 'a+')
f.write(con)
else:
logging.info("内容已经存在 %s" % _content)
except Exception, e:
logging.error("文件路径不存在 %s", e) def write_report(self, content):
"""
这个方法用于书写测试报告从而解决之前的通过
logging方式写入导致其他的日志无法实现写入
:param content: 传入文件的内容
:return: None
"""
reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
_reportName = reportName + cs.NOW
filename = cs.REPORT_PATH + _reportName
try:
file = open(filename, 'a+')
file.writelines(content)
except Exception, e:
logging.error("文件路径不存在 %s", e) def execute_case(self, filename):
"""
执行接口测试用例的方法
:param filename: 用例文件名称
:return: 测试结果
"""
conf.get_config(filename)
list = eval(conf.get_title_list()) for i in range(1, len(list)):
title = list[i] number = conf.get_data(title, key=cs.NUMBER) name = conf.get_data(title, key=cs.NAME)
method = conf.get_data(title, key=cs.METHOD)
url = conf.get_data(title, key=cs.URL)
data = conf.get_data(title, key=cs.DATA)
_data = request.json.dumps(data,ensure_ascii=False,indent=4)
headers = eval(conf.get_data(title, key=cs.HEADERS))
# headers['Cookie']=cookie
_headers = request.json.dumps(headers,ensure_ascii=False,indent=4) testUrl = cs.DOMAIN + url
login=cs.LOGIN
if(title==login):
actualCode = request.set_cookieApi(method, testUrl, data, headers)
else:
actualCode = str(request.api(method, testUrl, data, headers)) expectCode = str(conf.get_data(title, key=cs.CODE)) if actualCode != expectCode:
logging.info("新增一条接口失败报告")
self.write_report(cs.API_TEST_FAIL % (name, number, method, testUrl, headers,data, expectCode, actualCode))
else:
logging.info("新增一条接口成功报告")
self.write_report(cs.API_TEST_SUCCESS % (name, number, method, testUrl, headers,data, expectCode, actualCode)) def run_test(self, filename):
"""
普通接口测试类方法
:param filename: 接口的用例name
:return: 测试报告
"""
reportName =eval( conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT)) _filename = cs.REPORT_PATH + reportName + cs.NOW
try:
if os.path.exists(_filename):
os.remove(_filename)
self.execute_case(filename)
else:
self.execute_case(filename)
except Exception, e:
logging.error("执行接口测试失败 %s", e) def write_report_result(self):
"""
这个方法用于书写测试报告结果
:return: None
"""
reportName = eval(conf.get_data(title=cs.REPORT_NAME, key=cs.REPORT))
_filename = cs.REPORT_PATH + reportName + cs.NOW
try:
f = file(_filename)
content = f.read()
if content != None:
_count = content.count("Number")
_fail = content.count("Case Fail")
_pass = content.count("Case Pass")
space = content.split('\n')
space.insert(0,cs.RESULT_CONTENT % (_count, _pass, _fail))
_content_ = '\n'.join(space)
fp = file(_filename,'r+')
fp.write(_content_)
except Exception, e:
logging.error("文件路径不存在 %s", e)
run.py
# !/usr/bin/python
# -*- coding: UTF-8 -*-
# 执行包:runscript import function.func as func ApiTest = func.ApiTest() FILENAME = 'login.ini' """1.新建测试报告目录"""
ApiTest.new_report_menu(filename=func.cs.CASE_PATH+FILENAME) """2.执行测试用例"""
ApiTest.run_test(filename=func.cs.CASE_PATH+FILENAME) """3.统计测试报告结果"""
ApiTest.write_report_result()
配置文件:login.ini
[Test Report]
report = 'Enterprise Version'
reportName = 'Regression Testing Report' [login]
number = 1
name = login
method = post
url = /s1/web/login
data = {data:{'userCode':'admin','password':'admin'}}
headers = {'Content-Type': 'application/json;charset=UTF-8;'}
code = True [brand]
number = 2
name = get_brand
method = post
url = /s1/brand/getList
data = {"pageSize":10,"pageNum":1}
headers = {'Content-Type': 'application/json; charset=UTF-8;'}
code = True
constant.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 脚本功能:全部变量 import sys
import time
import os
reload(sys)
sys.setdefaultencoding('utf8') DOMAIN = 'http://****' REPORT_NAME = 'Test Report'
TITLE = 'All Data prepare the SQL' METHOD = 'method'
URL = 'url'
DATA = 'data'
NAME = 'name'
NUMBER = 'number'
CODE = 'code'
HEADERS = 'headers'
REPORT = 'report'
R_NAME = 'reportName'
LOGIN='login' REPORT_PATH = "../api4code/report/docs/"
YML_REPORT = "../api4code/report/mkdocs.yml" CASE_PATH = "../api4code/case/" #测试报告内容
API_TEST_FAIL = """
```
%s: Case Fail
Number: %s
Method: %s
Url: %s
Headers:
%s
Data :
%s
Expect : %s
Actual : %s
```
""" API_TEST_SUCCESS = """
```
%s: Case Pass
Number: %s
Method: %s
Url: %s
Headers:
%s
Data :
%s
Expect : %s
Actual : %s
```
""" #报告结果统计
RESULT_CONTENT = """
<p>Result:</p>
<table border="3" width="500px">
<tr>
<th style="color: #787878">All</th>
<th style="color: #3cc8b4">Pass</th>
<th style="color: #FFB5C5">Fail</th>
</tr>
<tr>
<th style="color: #787878">%s</th>
<th style="color: #3cc8b4">%s</th>
<th style="color: #FFB5C5">%s</th>
</tr>
</table>
""" NOW = '_' + time.strftime('%Y%m%d', time.localtime(time.time())) + '.md'
PROJECT_TIME = time.strftime('%Y%m%d', time.localtime(time.time()))
API 自动化框架的更多相关文章
- Python脚本之——API自动化框架总结
学完了Python脚本接口自动化之后,一直没有对该框架做总结,今天终于试着来做一份总结了. 框架结构如下图: 来说一下每个目录的作用: Configs:该目录下存放的是.conf,.ini文件格式的配 ...
- 多测师讲解a'pi自动化框架设计思想_高级讲师肖sir
API自动化框架API自动化框架分为conf.data.utils.api.testcase.runner.report.log8个模块.conf是用来储存系统环境.数据库.邮件等的配置参数.项目的绝 ...
- Appium移动自动化框架
引言:Appium 是一个移动端自动化测试开源工具,可以针对不同的平台用一套API来编写测试用例.本文对Appium自动化测试框架的功能进行了概括. 本文选自<软件自动化测试开发>. Ap ...
- CYQ.Data 从入门到放弃ORM系列:开篇:自动化框架编程思维
前言: 随着CYQ.Data 开始回归免费使用之后,发现用户的情绪越来越激动,为了保持这持续的激动性,让我有了开源的念头. 同时,由于框架经过这5-6年来的不断演进,以前发的早期教程已经太落后了,包括 ...
- Web自动化框架LazyUI使用手册(2)--先跑起来再说(第一个测试用例-百度搜索)
作者:cryanimal QQ:164166060 上篇文章中,简要介绍了LazyUI框架,本文便来演示,如何从无到有快速搭建基于lazyUI的工程,并成功运行第一个测试用例. 本文以百度搜索为例,选 ...
- python+request接口自动化框架
python+request接口自动化框架搭建 1.数据准备2.用python获取Excel文件中测试用例数据3.通过requests测试接口4.根据接口返回的code值和Excel对比 但本章只讲整 ...
- Android自动化框架介绍
随着Android应用得越来越广,越来越多的公司推出了自己移动应用测试平台.例如,百度的MTC.东软易测云.Testin云测试平台…….由于自己所在项目组就是做终端测试工具的,故抽空了解了下几种常见的 ...
- 转载:python + requests实现的接口自动化框架详细教程
转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实现的接口自动化框架详细教程 前段时间由于公司测试方向的转型,由 ...
- 接口自动化框架(java)--1.项目概述
项目github地址: https://github.com/tianchiTester/API_AutoFramework 这套框架的报告是自己封装的 1.测试基类TestBase: 接口请求的te ...
随机推荐
- LaTeX技巧892: Ubuntu 安装新版本TeXLive并更新
原文地址:http://www.latexstudio.net/archives/9788.html 摘要: 本文比较系统地介绍了在Ubuntu下的TeXLive的安装与配置测试过程,建议使用Ubun ...
- 【原创】大叔经验分享(18)hive2.0以后通过beeline执行sql没有进度信息
一 问题 在hive1.2中使用hive或者beeline执行sql都有进度信息,但是升级到hive2.0以后,只有hive执行sql还有进度信息,beeline执行sql完全silence,在等待结 ...
- 此主机支持Intel VT-x,但Intel VT-x处于禁用状态
原因:未开启虚拟化技术 解决方法:https://www.cnblogs.com/jiefu/p/10711955.html
- Centos查看系统CPU个数、核心数、线程数
1.查看 CPU 物理个数 grep 'physical id' /proc/cpuinfo | sort -u | wc -l 2.查看 CPU 核心数量 grep 'core id' /proc/ ...
- module.exports与exports
API文档是枯燥的,下面本人收集了一些论坛经常有人疑问和开源代码中经常遇到的案例供大家研究一下. module.exports与exports的区别 每一个node.js执行文件,都自动创建一个mod ...
- form组件
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['hobby'].choices ...
- nginx+apache动静分离/负载均衡
[主从] [Mysql-Master] log-bin=mysql-bin server-id = MariaDB [(none)]> grant replication slave on *. ...
- CodeForces 553E Kyoya and Train 动态规划 多项式 FFT 分治
原文链接http://www.cnblogs.com/zhouzhendong/p/8847145.html 题目传送门 - CodeForces 553E 题意 一个有$n$个节点$m$条边的有向图 ...
- 我是如何用redis做实时订阅推送的
前阵子开发了公司领劵中心的项目,这个项目是以redis作为关键技术落地的. 先说一下领劵中心的项目吧,这个项目就类似京东app的领劵中心,当然图是截取京东的,公司的就不截了... 其中 ...
- 导入Maven 工程pom.xml首行报错解决方法
1.利用IDE导入一个Maven工程,但是pom.xml文件首行报错,发现是maven版本需要升级 2.在pom.xml文件 增加配置 <properties> <maven-jar ...