python实现接口自动化测试


(周六日可以按照用例编写相关的接口测试用例,如果有验证码之类,给提供数据库查询或者固定验证码的可以。
web UI的也可以按照这个来,需要截图的地方,html报告中可查看执行过程中的截图)

模块分类

1、common(公用类)
2、config(配置类)
3、project(各个系统封装的API方法)
4、API_TC(测试案例)
5、TestFile(需要上传的或者其它使用的文件)
7、TestReport(保存执行结果)

common

主要是一些公用的类

  1. api_commonapi_common.py 封装了读取表格案例的request方法
import json
import re

import requests
import xlrd
from requests import packages

from common import tool
from config.config import *


def str_cmp(str1, str2):
    cmp_result = bool(re.fullmatch(str1, str2, re.IGNORECASE))
    return cmp_result


class RequestMethod(object):

    def __init__(self, request_url, json_data, headers, data_type, assert_content):
        packages.urllib3.disable_warnings()
        self.request_url = request_url
        self.json_data = json_data
        self.data_type = data_type
        self.assert_content = assert_content
        if type(headers).__name__ == 'dict':
            self.headers = headers
        else:
            self.headers = eval(headers)  # 将字符串转化为字典

    def post(self, cookies, *file):
        if self.data_type == "file":
            if len(file) > 1:
                data = eval(self.json_data)  # 使用字典
                file_path = file[0]
                file = {
                    file[1]: open(file_path, 'rb')
                }
                response = requests.post(self.request_url,
                                         data=data,
                                         files=file,
                                         cookies=cookies)
            else:
                data = eval(self.json_data)  # 使用字典
                file_path = file[0]
                file = {
                    'file': open(file_path, 'rb')
                }
                response = requests.post(self.request_url,
                                         data=data,
                                         files=file,
                                         cookies=cookies)
        else:
            if self.data_type == "form":
                data = eval(self.json_data)  # 使用字典
            if self.data_type == "json":
                data = json.dumps(eval(self.json_data))  # 将字典解析为json
            response = requests.post(self.request_url,
                                     data=data,
                                     headers=self.headers,
                                     cookies=cookies)
        if bool(tool.str_cmp("image/", response.headers['Content-Type'])):
            result_content = ('生成图片验证码').encode('utf-8')
        else:
            if response.headers['Content-Type'] == 'APPLICATION/OCTET-STREAM':
                result_content = response.content
            else:
                result_content = response.content.decode("utf-8")
        result_code = response.status_code

        result_session = response.cookies.get_dict()
        result_dict = {"result_content": result_content,
                       "result_code": result_code,
                       "result_session": result_session}
        if response.headers['Content-Type'] != 'APPLICATION/OCTET-STREAM':
            print(result_content)
            if self.assert_content != "":
                try:
                    assert (self.assert_content in result_content)
                except Exception as e:
                    print(self.assert_content)
                    assert False

        return result_dict

    def get(self, cookies):
        data = eval(self.json_data)  # 使用字典
        response = requests.get(self.request_url,
                                params=data,
                                headers=self.headers,
                                cookies=cookies)
        if bool(tool.str_cmp("image/", response.headers['Content-Type'])):
            result_content = ('生成图片验证码').encode('utf-8')
        elif bool(tool.str_cmp("text/", response.headers['Content-Type'])):
            result_content = ('导出').encode('utf-8')
        else:
            if response.headers['Content-Type'] == 'APPLICATION/OCTET-STREAM':
                result_content = response.content
            else:
                result_content = response.content.decode("utf-8")
            # result_json = response.json()
        result_code = response.status_code
        result_session = response.cookies.get_dict()
        result_dict = {"result_content": result_content,
                       "result_code": result_code,
                       # "result_json": result_json,
                       "result_session": result_session}
        if response.headers['Content-Type'] != 'APPLICATION/OCTET-STREAM':
            print(result_content)
            if self.assert_content != "":
                try:
                    assert (self.assert_content in result_content)
                except Exception as e:
                    print(self.assert_content)
                    assert False
        return result_dict


class ReadExcel(object):
    def __init__(self, file_path, sheet_name):
        self.file_path = file_path
        self.sheet_name = sheet_name
        self.table = self.load_excel()
        self.ncols = self.table.ncols
        self.nrows = self.table.nrows

    def load_excel(self):
        try:
            data = xlrd.open_workbook(self.file_path)
            table = data.sheet_by_name(self.sheet_name)
            return table
        except Exception as e:
            print(u"读表格错误")
            print(e)

    def get_col_number(self, row_number, row_name):
        # 表头名字为row_name的第row_number行,所对应的列1
        for i in range(self.ncols):
            if str_cmp(self.table.row_values(row_number)[i], row_name):
                return i

    def get_value(self, row_number, row_name):
        # 表头名字为row_name的第row_number行,获得这一列
        try:
            head_number = self.get_col_number(0, row_name)
            value = self.table.col_values(head_number)[row_number]
            return value
        except Exception as e:
            print("getCellData(%s,%s)" % (row_number, row_name))
            print(e)

    def for_test(self, number):
        url = (get_var("Origin", self.sheet_name) + self.get_value(number, u"请求URL"))
        data_list = [url,
                     self.get_value(number, u"参数"),
                     self.get_value(number, u"请求头"),
                     self.get_value(number, "数据格式"),
                     self.get_value(number, "响应信息")]
        return data_list

    def request_test(self, i, *par, **headers):
        default_header = eval(self.for_test(i)[2])
        if len(headers) > 0:
            default_header.update(headers)
        header = default_header
        # else:
        #     header = default_header
        data = self.for_test(i)[1] % par
        print(self.for_test(i)[0], data, header)
        return RequestMethod(self.for_test(i)[0],
                             data,
                             header,
                             self.for_test(i)[3],
                             self.for_test(i)[4]
                             )

工作中常用的方法:
1、用正则获取报文信息的并传递做为参数使用
2、按要求修改表格中数据,并保存

# from common import common

import datetime
import os
import re
import shutil
import time

from openpyxl import load_workbook


# 比对字符串,并打印结果
def str_cmp(str1, str2, str3="可以填写信息"):
    cmp_result = re.search(str(str1), str(str2), re.IGNORECASE)
    return cmp_result
    # if cmp_result is not None:
    #     return cmp_result
    # else:
    #     print(str3)
    #     print("预期结果:" + str1)
    #     print("实际结果:" + str2)


# 正则表达式
def regular(regex, content, index=1):
    search_result = '0'
    search = re.compile(regex)
    message = search.search(content)
    if message:
        if index == -1:
            search_result = message.groups()
        else:
            search_result = message.groups(index)
    return search_result[0]


# 生成债权
def create_loan(days, year_rate, period, money, area):
    save_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../test_file/loan.xlsx"))
    incoming_code = time.strftime("%Y%m%d%H%M%S", time.localtime())
    sn = incoming_code[4:]
    wb = load_workbook(filename=save_path)
    ws = wb['Sheet1']
    ws['A2'] = sn
    ws['C2'] = 'TS-A-' + sn
    ws['H2'] = incoming_code
    ws['E2'] = money
    ws['AT2'] = area
    now = datetime.datetime.now()
    delta = datetime.timedelta(days=days)
    loan_plan = now + delta
    ws['N2'] = loan_plan.strftime('%Y/%m/%d')
    ws['L2'] = year_rate
    ws['J2'] = period
    wb.save(save_path)
    wb.close()
    return 'TS-A-' + sn

# 导出进件后,添加出借人信息等并保存
def update_entry():
    save_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../TestFile/a.xlsx"))
    contract_code = "HT"+time.strftime("%Y%m%d%H%M%S", time.localtime())
    wb = load_workbook(filename=save_path)
    ws = wb['导出进件总表']
    ws['R2'] = "张某某"
    ws['V2'] = contract_code
    ws['W2'] = time.strftime("%Y/%m/%d", time.localtime())
    ws['X2'] = "18920196666"
    ws['Y2'] = "中国银行"
    ws['Z2'] = "收款银行明细什么鬼"
    ws['AA2'] = "6222019888888"
    ws['AB2'] = "中国银行"
    ws['AC2'] = "中国银行"
    ws['AD2'] = "110228198902260370"
    wb.save(save_path)
    wb.close()
    return contract_code


def copy_file(src_file, dst_file):
    if os.path.isfile(dst_file):
        os.remove(dst_file)  # 先删除已有的文件
    if not os.path.isfile(src_file):
        print("%s not exist!" % src_file)
    else:
        f_path, f_name = os.path.split(dst_file)  # 分离文件名和路径
        if not os.path.exists(f_path):
            os.makedirs(f_name)  # 创建路径
        shutil.copyfile(src_file, dst_file)  # 复制文件

def findall(reg, content):
    m = re.findall(reg, content)
    return m

def timstamp():
    a =str(int(time.time() * 1000))
    return a

if __name__ == '__main__':
    print("test here")

自动不重复生成身份证信息及生日,每天最多999个

from datetime import date
from config.config import *
import random
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
districtcode_file = parent_dir + "/common/districtcode.txt"

def getdistrictcode():
    codelist = []
    codecity = []
    file = open(districtcode_file,"r",encoding="utf-8")
    lines = file.readlines()  # 逐行读取
    for line in lines:
        if line.lstrip().rstrip().strip() != '' and (line.lstrip().rstrip().strip())[:6][-2:] != '00':
            # 如果每行中去重后不为空,并且6位数字中最后两位不为00,则添加到列表里。(最后两位为00时为省份或地级市代码)
            codelist.append(line[:6])
            codecity.append(line[10:])

    return codelist,codecity


def gennerator():
    da = date.today()
    codelist = getdistrictcode()[0]
    id = codelist[random.randint(0, len(codelist))]  # 地区项
    year = str(int(da.strftime('%Y'))-24)
    id = id + year
    id = id + da.strftime('%m%d')
    if da.strftime('%m%d') != get_var("date"):
        set_var("date", da.strftime('%m%d'))
        set_var("sequence", "1")
    else:
        set_var("sequence", str(int(get_var("sequence"))+1))
    sequence = "%03d" % int(get_var("sequence"))
    id = id + sequence  # ,顺序号简单处理
    i = 0
    count = 0
    weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]  # 权重项
    checkcode = {'0': '1', '1': '0', '2': 'X', '3': '9', '4': '8', '5': '7', '6': '6', '7': '5', '8': '5', '9': '3',
                 '10': '2'}  # 校验码映射
    for i in range(0, len(id)):
        count = count + int(id[i]) * weight[i]
    id = id + checkcode[str(count % 11)]  # 算出校验码
    birthDate = da.strftime('%Y-%m-%d')
    return id,birthDate


if __name__ == '__main__':
    a = gennerator()
    print(a[0],a[1])
    print(parent_dir)

config 获取配置变量或者修改变量存储以待使用(参数化及关联一体化)

from configobj import ConfigObj
import os

cur_path = os.path.dirname(os.path.realpath(__file__))
configPath = os.path.join(cur_path, "config.ini")
cf = ConfigObj(configPath, encoding="UTF8")


def get_var(key, session="var"):
    var = cf[session][key]
    return var


def set_var(key, value, session="var"):
    cf[session][key]=value
    cf.write()
    # cf.write(open(configPath, "r+", encoding="utf-8"))


if __name__ == '__main__':
    print(get_var("productNo"), type(get_var("productNo")))

Project 项目api封装实例

from common import api_common, tool
from config.config import *

parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
zong_he_ye_wu = api_common.ReadExcel(parent_dir + "/TestFile/hyzh.xlsx", "zong_he_ye_wu")  # 综合业务


class ZH(object):
    # 用户系统登录,需要提供用户名和密码
    def login(self, user_account, pwd):
        request_demo = zong_he_ye_wu.request_test(1, user_account, pwd).post(None)
        set_var("zh_session", str(request_demo["result_session"]))  # 登录成功后,记住session


if __name__ == '__main__':
    zh = ZH()
    zh.login("admin", "123456")

TC 用unittest组织不同场景的测试用例

TestFile中Excel表格模版

python实现接口自动化测试

TestReport生成的保存存储的地方

以上功能实现了,接口流程用例执行及邮件抄送执行报告
python实现接口自动化测试