公司内部的一个接口自动化使用框架(非使用工具)
工作原理: 测试用例在excel上编辑,使用第三方库xlrd,读取表格sheet和内容,sheetName对应模块名,Jenkins集成服务发现服务moduleName查找对应表单,运用第三方库requests请求接口,根据结果和期望值进行断言,根据输出报告判断接口测试是否通过。
1. 数据准备
数据插入(容易实现的测试场景下所需外部数据)
准备sql (接口需要重复使用,参数一定得是变量)
2.集成部署(运维相关了解即可)
平滑升级验证脚本加入自动化
3.自动化框架实现
●调用mysql
●excel遍历测试用例
●requests实现接口调用
●根据接口返回的code值和Excel对比
●报告反馈
●暴露服务
写一个简单登录的接口自动化测试
代码的分层如下图:
coding.png
一、写一个封装的获取excel表格的模块
excel.png
代码实现如下:
# !/usr/bin/python # -*- coding: UTF-8 -*- # 基础包:excel的封装 import xlrd workbook = None def open_excel(path): """打开excel""" global workbook if (workbook == None): workbook = xlrd.open_workbook(path, on_demand=True) def get_sheet(sheetName): """获取页名""" global workbook return workbook.sheet_by_name(sheetName) def get_rows(sheet): """获取行号""" return sheet.nrows def get_content(sheet, row, col): """获取表格中内容""" return sheet.cell(row, col).value def release(path): """释放excel减少内存""" global workbook workbook.release_resources() del workbook |
代码封装后当成模块引用,这还是最开始呢。
二、引用log模块获取日志
准备工作:
需要一个日志的捕获,包括框架和源码抛出的expection。
代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 基础包:日志服务 import logging import time def getLogger(): global tezLogPath try: tezLogPath except NameError: tezLogPath = "/data/log/apiTest/" FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' # file = tezLogPath + time.strftime("%Y-%m-%d", time.localtime()) + ".log" # logging.basicConfig(filename=file, level=logging.INFO, format=FORMAT) # 开发阶段为了方便调试,可不输出到文件 logging.basicConfig(level=logging.INFO, format=FORMAT) return logging |
三、引用requests模块接口测试
准备工作:
需要的请求类型和执行测试的方法。
代码如下:
#!/usr/bin/python# #-*- coding: UTF-8 -*- # 基础包:接口测试的封装 import requests import tezLog as log logging = log.getLogger() def api_test(method, url, data ,headers): """ 定义一个请求接口的方法和需要的参数 :Args: method - 企业名称 str url - 用户昵称 str data - 参数 str headers - 请求头信息 dict 非RESTful API请求另外的请求类型实际用不到。也不安全。 """ try: if method == "post": results = requests.post(url, data, headers=headers) if method == "get": results = requests.get(url, data, headers=headers) # if method == "put": # results = requests.put(url, data, headers=headers) # if method == "delete": # results = requests.delete(url, headers=headers) # if method == "patch": # results == requests.patch(url, data, headers=headers) # if method == "options": # results == requests.options(url, headers=headers) response = results.json() code = response.get("code") return code except Exception, e: logging.error("service is error", e) |
四、关于common模块
主要调用二次封装的代码,结合业务做一个通用代码。如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 业务包:通用函数 import core.tezMysql as mysql import core.tezLog as log import gl import core.tezExcel as excel import core.tezRequest as request from prettytable import PrettyTable filename = gl.FILE_NAME logging = log.get_logger() def prepare_data(host, user, password, db, sql): """数据准备,添加测试数据""" 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_excel_sheet(path, module): """依据模块名获取sheet""" excel.open_excel(path) return excel.get_sheet(module) def replace_holder(value): """遍历字典替换占位符""" for holder in gl.PLACE_HOLDER: value = value.replace(holder, gl.PLACE_HOLDER[holder]) return value def get_prepare_sql(sheet): """获取预执行SQL""" return replace_holder(excel.get_content(sheet, gl.SQL_ROW, gl.SQL_COL)) def run_test(sheet, url): """再执行测试用例""" rows = excel.get_rows(sheet) fail = 0 for i in range(2, rows): testNumber = str(int(excel.get_content(sheet, i, gl.CASE_NUMBER))) testData = excel.get_content(sheet, i, gl.CASE_DATA) testName = excel.get_content(sheet, i, gl.CASE_NAME) testUrl = excel.get_content(sheet, i, gl.CASE_URL) testUrl = url + testUrl testMethod = excel.get_content(sheet, i, gl.CASE_METHOD) testHeaders = str(excel.get_content(sheet, i, gl.CASE_HEADERS)) testHeaders = eval(replace_holder(testHeaders)) testCode = excel.get_content(sheet, i, gl.CASE_CODE) actualCode = request.api_test(testMethod, testUrl, testData, testHeaders) expectCode = str(int(testCode)) failResults = PrettyTable(["Number", "Method", "Url", "Data", "ActualCode", "ExpectCode"]) failResults.align["Number"] = "l" failResults.padding_width = 1 failResults.add_row([testNumber, testMethod, testUrl, testData, actualCode, expectCode]) if actualCode != expectCode: logging.info("FailCase %s", testName) print "FailureInfo" print failResults fail += 1 else: logging.info("Number %s", testNumber) logging.info("TrueCase %s", testName) if fail > 0: return False return True |
五、关于参数中gl模块
准备工作:
所有的参数和常量我们会整理到这个文件中,因为设计业务和服务密码、数据库密码这里展示一部分。
代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 脚本功能:全部变量 import time import uuid CASE_NUMBER = 0 # 用例编号 CASE_NAME = 1 # 用例名称 CASE_DATA = 2 # 用例参数 CASE_URL = 3 # 用例接口地址 CASE_METHOD = 4 # 用例请求类型 CASE_CODE = 5 # 用例code CASE_HEADERS = 6 # 用例headers SQL_ROW = 0 # 预执行SQL的行号 SQL_COL = 1 # 预执行SQL的列号 |
六、写一个run文件:只是用来执行的,业务和代码剥离。
代码如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- # 验证包:接口测试脚本 import sys import core.tezLog as log import function.common as common logging = log.getLogger() """1.外部输入参数""" path = sys.path[0] # 当前路径 module = sys.argv[1] # 服务模块名 url = sys.argv[2] # 服务地址 host = sys.argv[3] # 数据库地址 user = sys.argv[4] # 数据库用户名 password = sys.argv[5] # 数据库密码 db = sys.argv[6] # 数据库名称 """2.根据module获取Sheet""" logging.info("-------------- Execute TestCases ---------------") sheet = common.get_excel_sheet(path + "/" + common.filename, module) """3.数据准备""" logging.info("-------------- Prepare data through MysqlDB --------------") sql = common.get_prepare_sql(sheet) common.prepare_data(host=host, user=user, password=password, db=db, sql=sql) """4.执行测试用例""" res = common.run(sheet, url) logging.info("-------------- Get the result ------------ %s", res) """这里的res是我们平滑升级的时候需要返回结果为TRUE才会继续下面走。""" |