python+requests+excel 接口自动化测试框架(一)

前言:该框架总结自某学习网站的视频

一、 接口测试用例

运行前:

运行后:(10条通过,1条失败;通过即显示为pass,未通过则显示响应结果)

主要信息有:接口地址、请求类型、请求数据、预期结果、header和数据依赖,其中数据依赖是难点

二、封装操作excel的函数

创建文件 utils(文件夹名,下同)/operation_excel.py(文件名,下同)

#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import xlrd
from xlutils.copy import copy


class OperationExcel(object):
    # 构造函数
    def __init__(self, file_name=None, sheet_id=None):
        # 如果指定表格信息,则使用指定的表格;若无指定,则使用默认的表格
        if file_name:
            self.file_name = file_name
            self.sheet_id = sheet_id
        else:
            self.file_name = '../data/imooc_case.xls'
            self.sheet_id = 0
        self.sheet = self.get_sheet()

    # 获取要操作的表格
    def get_sheet(self):
        table = xlrd.open_workbook(self.file_name)
        sheet = table.sheets()[self.sheet_id]
        return sheet

    # 获取单元格的行数
    def get_lines(self):
        return self.sheet.nrows

    # 获取单元格的列数
    def get_cols(self):
        return self.sheet.ncols

    # 获取某个单元格的内容
    def get_cell_value(self, row, col):
        # 注意不要把小括号写成中括号
        return self.sheet.cell_value(row, col)

    # 写入数据
    def write_value(self, row, col, value):
        read_data = xlrd.open_workbook(self.file_name)
        write_data = copy(read_data)
        sheet_data = write_data.get_sheet(0)
        sheet_data.write(row, col, value)
        write_data.save(self.file_name)

    # 获取某一列的内容
    def get_cols_data(self, col_id=None):
        if col_id != None:
            cols = self.sheet.col_values(col_id)
        else:
            cols = self.sheet.col_values(0)
        return cols

    # 根据对应的case_id找到对应行的行号
    def get_row_num(self, case_id):
        num = 0
        cols_data = self.get_cols_data()
        for col_data in cols_data:
            if case_id in col_data:
                return num
            num = num+1

    # 根据行号,找到该行的内容
    def get_row_values(self, row):
        row_data = self.sheet.row_values(row)
        return row_data

    # 根据对应的case_id找到对应行的内容
    def get_rows_data(self, case_id):
        row_num = self.get_row_num(case_id)
        rows_data = self.get_row_values(row_num)
        return rows_data

三、 封装操作json文件(接口请求数据)方法

1、创建文件 data/user.json ,存储所有接口的请求数据。这些数据可以单个调式接口的时候,用fiddler搜集

2、创建文件 utils/operation_json.py

import json


class OperationJson(object):
    def __init__(self, file_path=None):
        if file_path == None:
            self.file_path = '../data/user.json'
        else:
            self.file_path = file_path
        self.data = self.read_data()

    # 读取json文件
    def read_data(self):
        '''
        load:针对文件句柄,将json格式字符转换成dict,从文件中读取
        loads:针对内存对象,将string转换成dict
        总结:不带s的是针对文件的操作,dumps同理
        '''
        with open(self.file_path) as file:
            data = json.load(file)
            return data

    # 获取请求数据
    def get_data(self, id):
        values = self.data[id]
        return values

    # 写json
    def write_data(self, data):
        with open('../data/cookie.json', 'w') as file:
            file.write(json.dumps(data))

四、 封装获取常量方法

创建文件 dataconfig/data_config.py

class GlobalVar(object):
    '''
    id,模块,url,是否运行,请求类型,是否携带header,case依赖,依赖的返回数据,
    数据依赖字段,请求数据,预期结果、实际结果
    '''
    id = '0'
    request_name = '1'
    url = '2'
    run = '3'
    request_method = '4'
    header = '5'
    case_depend = '6'
    data_depend = '7'
    field_depend = '8'
    data = '9'
    expect = '10'
    result = '11'

    # 获取caseId
    def get_id(self):
        return GlobalVar.id

    # 获取url
    def get_url(self):
        return GlobalVar.url

    def get_run(self):
        return GlobalVar.run

    def get_request_method(self):
        return GlobalVar.request_method

    def get_header(self):
        return GlobalVar.header

    def get_case_depend(self):
        return GlobalVar.case_depend

    def get_data_depend(self):
        return GlobalVar.data_depend

    def get_field_depend(self):
        return GlobalVar.field_depend

    def get_data(self):
        return GlobalVar.data

    def get_expect(self):
        return GlobalVar.expect

    def get_result(self):
        return GlobalVar.result

五、 封装获取接口数据方法

创建文件 dataconfig/get_data.py

from utils.operation_excel import OperationExcel
from utils.operation_json import OperationJson
from utils.connect_db import OperationMysql
from dataconfig.data_config import GlobalVar


class GetData(object):
    def __init__(self):
        self.opera_excel = OperationExcel()
        self.global_val = GlobalVar()

    # 获取case的个数
    def get_case_lines(self):
        return self.opera_excel.get_lines()

    # 获取是否执行,把行数入参
    def get_is_run(self, row):
        # flag = None
        col = int(self.global_val.get_run())
        run = self.opera_excel.get_cell_value(row, col)
        if run == "yes":
            flag = True
        else:
            flag = False
        return flag

    # 是否携带header,携带的话直接返回header内容
    def get_is_header(self, row):
        col = int(self.global_val.get_header())
        header = self.opera_excel.get_cell_value(row, col)
        if header == "":
            return None
        return header

    # 获取请求方式
    def get_request_method(self, row):
        col = int(self.global_val.get_request_method())
        request_method = self.opera_excel.get_cell_value(row, col)
        return request_method

    # 获取url
    def get_url(self, row):
        col = int(self.global_val.get_url())
        url = self.opera_excel.get_cell_value(row, col)
        return url

    # 获取请求数据
    def get_request_data(self, row):
        col = int(self.global_val.get_data())
        data = self.opera_excel.get_cell_value(row, col)
        if data == "":
            return None
        return data

    # 通过获取关键字拿到data数据,从json文件中读取
    def get_data_from_json(self, row):
        opera_json = OperationJson()
        data = opera_json.get_data(self.get_request_data(row))
        return data

    # 获取预期结果
    def get_expect_data(self, row):
        col = int(self.global_val.get_expect())
        expect = self.opera_excel.get_cell_value(row, col)
        if expect == "":
            return None
        return expect

    # 通过sql获取预期结果
    def get_expect_data_from_mysql(self, row):
        opera_mysql = OperationMysql()
        sql = self.get_expect_data(row)
        result = opera_mysql.search_one(sql)
        # decode('unicode-escape')反向编码字符成汉字
        return result.decode('unicode-escape')

    # 写入数据
    def write_result(self, row, value):
        col = int(self.global_val.get_result())
        self.opera_excel.write_value(row, col, value)

    # 判断是否有case依赖
    def get_is_depend(self, row):
        col = int(self.global_val.get_case_depend())
        case_depend = self.opera_excel.get_cell_value(row, col)
        if case_depend == "":
            return None
        return case_depend

    # 获取依赖数据的key
    def get_depend_key(self, row):
        col = int(self.global_val.get_data_depend())
        depend_key = self.opera_excel.get_cell_value(row, col)
        if depend_key == "":
            return None
        return depend_key

    # 获取数据依赖字段
    def get_depend_field(self, row):
        col = int(self.global_val.get_field_depend())
        depend_field = self.opera_excel.get_cell_value(row, col)
        if depend_field == "":
            return None
        return depend_field

六、 get和post基类的封装

创建文件 base/run_method.py

import requests
import json


class RunMethod(object):
    def post_main(self, url, data, headers=None):
        if headers != "None":
            res = requests.post(url=url, data=data, headers=headers)
        else:
            res = requests.post(url=url, data=data)
        # res.content.decode('utf8')
        return res.json()

    def get_main(self, url, data=None, headers=None):
        if headers != None:
            res = requests.get(url=url, data=data, headers=headers, verify=False)
        else:
            res = requests.get(url=url, data=data, verify=False)
        return res.json()

    def run_main(self, method, url, data=None, headers=None):
        if method == "Post":
            res = self.post_main(url, data, headers)
        else:
            res = self.get_main(url, data, headers)
        # 因为json.dumps 序列化时对中文默认使用的ascii编码.想输出真正的中文需要指定ensure_ascii=False
        return json.dumps(res, ensure_ascii=False)
        # return json.dumps(res, ensure_ascii=False, sort_keys=True, indent=2)

七、预期结果和实际结果判断

创建文件 utils/common_util.py

import json
import operator


class CommonUtil(object):
    # 判断一个字符串是否在另一个字符串中
    def is_contain(self, str_one, str_two):
        # isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()
        '''
        if isinstance(str_one, str):
            str_one = str_one.encode("unicode-escape").decode("string-escape")
        '''
        flag = operator.contains(str_two, str_one)
        return flag

八、 运行方法封装

创建文件 main/run_test.py

from base.run_method import RunMethod
from dataconfig.get_data import GetData
from utils.common_util import CommonUtil


class RunTest(object):
    def __init__(self):
        self.data = GetData()
        self.run_method = RunMethod()
        self.com_util = CommonUtil()
        # self.send_mail = SendEmail()

    # 执行程序
    def go_on_run(self):
        pass_count = []
        fail_count = []
        # 下标从0开始
        rows_count = self.data.get_case_lines()
        # 从下标1开始循环取数据,忽略第一行表头数据
        for i in range(1, rows_count):
            is_run = self.data.get_is_run(i)
            if is_run:
                method = self.data.get_request_method(i)
                url = self.data.get_url(i)
                # data = self.data.get_request_data(i)
                data = self.data.get_data_from_json(i)
                headers = self.data.get_is_header(i)
                # expect = self.data.get_expect_data_from_mysql(i)
                expect = self.data.get_expect_data(i)

                res = self.run_method.run_main(method, url, data, headers)

                if self.com_util.is_contain(expect, res):
                    self.data.write_result(i, 'pass')
                    pass_count.append(i)
                else:
                    self.data.write_result(i, res)
                    fail_count.append(i)
        print("成功的用例数:", len(pass_count))
        print("失败的用例数:", len(fail_count))
        # self.send_mail.send_main(pass_count, fail_count)


if __name__ == '__main__':
    run = RunTest()
    run.go_on_run()

运行结果:

发布了26 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/changyixue/article/details/100514868