python数据驱动--Excel维护测试用例

自动化测试经常使用csv文件进行数据驱动测试,读写方法总结如一下

第1步: 学会读取CSV文件

CSV文件.jpg
代码参考.jpg
'''
Created on 2018年3月1日
@author: Yvon_早安阳光
'''
import csv
# 读取csv文件方式1
csvfile = open('shuju.csv','r')
reader = csv.reader(csvfile)#返回的是迭代类型
data =[]          #中括号[]代表list列表数据类型,列表是一种可变的序列
for item in reader:
    print(item)
    data.append(item)
print(data)
csvfile.close()
 
print('-------------------------------------------------------------------------------------------------------')
#读取csv文件方式2
with open ('shuju.csv','r') as csvfile:
    reader1 = csv.reader(csvfile)#返回的是迭代类型
    for item1 in reader1:
        print(item1) #打印所有的数据
        colum = [item1[2]] #获取第3列
        print(colum)
csvfile.close()
 
print('-------------------------------------------------------------------------------------------------------')
#读取csv文件方式3
'''
使用DictReader,和reader函数类似,接收一个可迭代的对象,能返回一个生成器,
但是返回的每一个单元格都放在一个字典的值内,而这个字典的键则是这个单元格的标题(即列头)
'''
with open('shuju.csv','r') as csvfile2:
    reader2 = csv.DictReader(csvfile2)
    colum = [row for row in reader2]
    colum1 = [row['语言'] for row in colum]
print(colum)
print(colum1)
读取csv文件方式3.jpg

第2步:学会写入CSV文件

写入方法1.jpg
写入方法2和3.jpg
'''
Created on 2018年3月2日
@author: fajin
'''
import pandas as pd 
#写入csv文件方式1--使用Pandas模块
name = ["序号","语言","测试工具"]
list = [['1','VB','QTP'],['2','Python','Appium手机'],['3','日本Ruby','Selenium']]
# test = pd.DataFram(columns = name,data = list)
test = pd.DataFrame(columns = name,data = list)
test.to_csv('shuju1.csv',index=False,sep=',',encoding="gb2312")#避免中文乱码
 
print('--------------------------------------------------------')
 
import csv
 
#写入csv文件方式2---从列表写入csv文件
#读取csv文件,写入新的csv文件
 
csvfile = open('shuju.csv','r')
reader = csv.reader(csvfile)#返回的是迭代类型
data =[]          #中括号[]代表list列表数据类型,列表是一种可变的序列
for item in reader:
    data.append(item)
print(data)
csvfile.close()
 
csvFile2 = open('shuju2.csv','w', newline='') # 设置newline,否则两行之间会空一行 
writer = csv.writer(csvFile2)
m = len(data)
for i in range(m):
    writer.writerow(data[i])
csvFile2.close()
 
#写入csv文件方式3---从字典写入csv文件  貌似适合2列
dic = {"序号":["语言","测试工具"]}
csvFile3 = open('shuju3.csv','w', newline='') 
writer2 = csv.writer(csvFile3)
for key in dic:
    writer2.writerow([key, dic[key]])
csvFile3.close()

第3步: 实战Excel数据驱动自动化测试

Excel数据驱动维护测试用例

Excel维护测试用例.jpg

ExcelConfig.py 脚本文件 定义Header头

# -*- coding: utf-8 -*-
# @Time : 2020/12/1 20:52
# @File : ExcelConfig.py
# @Author : Yvon_₯㎕ζ๓

#定义类
class DataConfig:
   #定义列属性
    #用例ID   模块  接口名称    请求URL   前置条件    请求类型    请求参数类型
    #请求参数   预期结果    实际结果    备注  是否运行    headers cookies status_code 数据库验证
    #用例ID
    case_id = "用例ID"
    case_model = "模块"
    case_name = "接口名称"
    url = "请求URL"
    pre_exec = "前置条件"
    method = "请求类型"
    params_type = "请求参数类型"
    params = "请求参数"
    expect_result = "预期结果"
    actual_result = "实际结果"
    is_run = "是否运行"
    headers = "headers"
    cookies = "cookies"
    code = "status_code"
    db_verify = "数据库验证"

ExcelUtil 读写Excel文件

# -*- coding: utf-8 -*-
# @Time : 2020/11/26 17:43
# @File : ExcelUtil.py
# @Author : Yvon_懿払曦

import os
import xlrd ,json
from config.Conf import ConfigYaml
from config import Conf


#目的:参数化,pytest list文件形式读取
# 自定义异常
class SheetTypeError:
    pass
#1、验证文件是否存在,存在读取,不存在报错
class ExcelReader:
    def __init__(self,excel_file,sheet_by):
        if os.path.exists(excel_file):
            self.excel_file = excel_file
            self.sheet_by = sheet_by
            self._data = list()
        else:
            raise FileNotFoundError("文件不存在")

#2、读取sheet方式.名称,索引
    def data(self):
        # 存在不读取,不存在读取
        if not self._data:
            workbook = xlrd.open_workbook(self.excel_file)
            if type(self.sheet_by)  not in [str,int]:
                raise SheetTypeError("请输入int or str")
            elif type(self.sheet_by) == int:
                sheet = workbook.sheet_by_index(self.sheet_by)  # int型
            elif type(self.sheet_by) == str:
                sheet = workbook.sheet_by_name(self.sheet_by)  # str型

    #3、sheet内容
            # 返回list,元素:字典
            #格式[{'company': '可口可乐', 'manager': 'Shirley'}, {'company': '北极光', 'manager': 'marry'}]
            #1.获取首行信息
            title = sheet.row_values(0)
            #2.遍历测试行,与首行组成dict,放在list
                #1.循环,过滤首行,从1开始
            for col in range(1,sheet.nrows):
                col_value = sheet.row_values(col)
                #2.与首行组成字典,放list
                self._data.append(dict(zip(title, col_value)))

#4、返回结果
        return self._data

if __name__ == "__main__":
    case_file = os.path.join(Conf.get_data_path(), ConfigYaml().get_excel_file())  # 拼接路径+文件
    # print(case_file)
    # 2).测试用例sheet名称
    sheet_name = ConfigYaml().get_excel_sheet()

    reader = ExcelReader(case_file,sheet_name)
    # reader = ExcelReader("../data/testdata.xlsx", "美多商城接口测试")
    result = reader.data()
    # print(result)
    print(json.dumps(result, sort_keys=True, ensure_ascii=False, indent=4, separators=(', ', ': ')))  # Json格式打印
读取Excel数据.jpg

ExcelData.py脚本读取有效测试用例

  • 根据运行列是否==y,获取测试用例
  • 获取全部的测试用例
  • 从获取全部的测试用例中获取前置条件测试用例
# -*- coding: utf-8 -*-
# @Time : 2020/11/27 20:17
# @File : ExcelData.py
# @Author : Yvon_懿払曦

from utils.ExcelUtil import ExcelReader
# import json
from common.ExcelConfig import DataConfig

class Data:
    def __init__(self,case_file,sheet_name):
    #1、使用excel工具类,获取结果list
        # self.reader = ExcelReader("../data/testdata.xlsx","美多商城接口测试")
        self.reader = ExcelReader(case_file, sheet_name)  #文件名、sheet_name参数化


    #2、列是否运行内容,y
    def get_run_data(self):
        """
        根据运行列是否==y,获取测试用例
        :return:
        """
        run_list = list()
        for line in self.reader.data():
            #if line[DataConfig.is_run] == "y":
            if str(line[DataConfig().is_run]).lower() == "y":   #大小写转换Y
                # print(line)
                #print(json.dumps(line, sort_keys=True, ensure_ascii=False, indent=4, separators=(', ', ': ')))  # Json格式打印
                run_list.append(line)
        # print(json.dumps(run_list, sort_keys=True, ensure_ascii=False, indent=4, separators=(', ', ': ')))  # Json格式打印
        return run_list


    def get_case_list(self):
        """
        获取全部的测试用例
        :return:
        """
        #方法一
        # run_list = list()
        # for line in self.reader.data():
        #     run_list.append(line)
        # return  run_list

        # 方法二  列表推导
        run_list = [line for line in self.reader.data()]
        return run_list


    def get_case_pre(self,pre):
        #获取全部测试用例
        #list判断、执行、获取
        """
        根据前置条件:从全部测试用例取到测试用例
        :param pre:
        :return:
        """
        run_list = self.get_case_list()
        for line in run_list:
            if pre in dict(line).values():
                return line
        return None

执行test_excel_case.py脚本

从Excel中读取测试用例,做到数据分离,代码中维护参数即可,所有测试数据在Excel中维护

# -*- coding: utf-8 -*-
# @Time : 2020/12/2 11:21
# @File : test_excel_case.py
# @Author : Yvon_₯㎕ζ๓
from config.Conf import ConfigYaml
from config import Conf
from common.ExcelData import Data
from common.ExcelConfig import DataConfig
from common import ExcelConfig
from common import Base
from utils.RequestsUtil import Request
from utils.AssertUtil import AssertUtil
from utils.LogUtil import my_log
import os,json,pytest
import allure

#1、初始化信息
#1).初始化测试用例文件
case_file = os.path.join(Conf.get_data_path(),ConfigYaml().get_excel_file()) # 拼接路径+文件
# print(case_file)
#2).测试用例sheet名称
sheet_name = ConfigYaml().get_excel_sheet()
# print(sheet_name)
#3).获取运行测试用例列表
data_init = Data(case_file,sheet_name)
run_list = data_init.get_run_data()
print(run_list)
# print(json.dumps(run_list, sort_keys=True, ensure_ascii=False, indent=4, separators=(', ', ': ')))  # Json格式打印
#4).日志
log = my_log()
#初始化DataConfig
# data_key = DataConfig()
data_key = ExcelConfig.DataConfig
#2、测试用例方法、参数化运行
#先用一个用例去调试

class TestExcel:
    def run_api(self,url,method,params=None,header=None,cookie=None):
        """
        发送请求api
        :return:
        """
        # 接口请求
        request = Request()
        # params 转义json
        #验证params 有没有内容
        if len(str(params).strip()) != 0:
            params = json.loads(params)
        #method post/get
        if str(method).lower()=="get":
            #增加headers,cookies
            res = request.get(url,json = params,headers = header,cookies = cookie)
        elif str(method).lower()=="post":
            res = request.post(url, json=params,headers = header,cookies = cookie)
        else:
            log.error("错误请求method: %S"% method)
        # print(res)
        return res

    def run_pre(self,pre_case):
        """
        前置条件运行
        :param pre_case:
        :return:
        """
        pass
        url = ConfigYaml().get_conf_url() + pre_case[data_key.url]
        method = pre_case[data_key.method]
        params = pre_case[data_key.params]
        headers = pre_case[data_key.headers]
        cookies = pre_case[data_key.cookies]
        header = Base.json_parse(headers)
        cookie = Base.json_parse(cookies)
        res = self.run_api(url,method,params,header)
        print("前置用例执行: %s"%res)
        return res

#1).初始化信息url,data
    #1、增加pytest
    @pytest.mark.parametrize("case",run_list)
    #2、修改方法参数
    def test_run(self,case):
        #run_list 第一个用例,用例,key获取values
        url = ConfigYaml().get_conf_url() +case[data_key.url]
        print(url)
        case_id = case[data_key.case_id]
        # print(case_id)
        case_model = case[data_key.case_model]
        case_name = case[data_key.case_name]
        pre_exec = case[data_key.pre_exec]
        method = case[data_key.method]
        params_type = case[data_key.params_type]
        params = case[data_key.params]
        expect_result = case[data_key.expect_result]
        headers = case[data_key.headers]
        cookies = case[data_key.cookies]
        code = case[data_key.code]
        db_verify = case[data_key.db_verify]

        #动态headers请求
        ##1.验证前置条件
        if pre_exec:
            pass

        ##2.找到执行用例
            pre_case = data_init.get_case_pre(pre_exec)
            print("前置条件信息为: %s" %pre_case)
            pre_res = self.run_pre(pre_case)
            headers,cookies = self.get_correlation(headers,cookies,pre_res)

        header = Base.json_parse(headers)
        cookie = Base.json_parse(cookies)
        res = self.run_api(url, method, params, header, cookie)
        print("测试用例执行: %s" % res)
        # return res  # 注意

        # sheet名称--feature 一级标签
        allure.dynamic.feature(sheet_name)
        # 模块--story 二级标签
        allure.dynamic.story(case_model)
        # 用例ID + 接口名称 - - title
        allure.dynamic.title(case_id+case_name)
        #请求URL 请求类型 期望结果 实际结果 description
        # allure.dynamic.description(url+method+expect_result+res)
        desc = "<font color='green' size=3>请求URL: </font> {}<Br/>" \
               "<font color='green' size=3>请求类型: </font>{}<Br/>" \
               "<font color='red' size=3>期望结果: </font>{}<Br/>" \
               "<font color='green' size=3>实际结果: </font>{}".format(url, method, expect_result, res)
        allure.dynamic.description(desc)

        #1.断言验证
        #2.状态码,返回结果内容,数据库相关结果验证
        #"""断言验证--状态码,返回结果内容,数据库相关的结果的验证"""
        #1.)状态码
        assert_util = AssertUtil()
        assert_util.assert_code(int(res["code"]),int(code))
        #2.)返回结果内容验证
        assert_util.assert_in_body(str(res["body"]),str(expect_result))
        #********数据库结果断言********
        Base.assert_db("db_1",res["body"],db_verify)

    def get_correlation(self,headers,cookies,pre_res):
        """
        关联
        :param headers:
        :param cookies:
        :param pre_res:
        :return:
        """
        #验证是否有关联
        headers_para,cookies_para = Base.params_find(headers,cookies)
        #有关联,执行前置用例,获取结果
        if len(headers_para):
            headers_data = pre_res["body"][headers_para[0]]
        #结果替换
            headers = Base.res_sub(headers,headers_data)

        #有关联,执行前置用例,获取结果
        if len(cookies_para):
            cookies_data = pre_res["body"][cookies_para[0]]
        #结果替换
            cookies = Base.res_sub(headers,cookies_data)
        return headers, cookies


if __name__ == "__main__":
    # pass
    # TestExcel().test_run()
    # pytest.main(["-s","test_excel_case.py"])
    report_path = Conf.get_report_path()+os.sep+"result"
    report_html_path = Conf.get_report_path()+os.sep+"html"

    pytest.main(["-s", "test_excel_case.py", "--alluredir", report_path ])
    # Base.allure_report(report_path, report_html_path)
    # Base.send_mail(title="接口测试报告结果", content=report_html_path)
Excel数据驱动调用接口.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容