山东省建设教育集团网站首页,重庆的seo服务公司,腾讯网,建设部网站上怎样查询企业业绩经过一周多时间#xff0c;基于pythonpytestexcelallure框架的接口自动化测试初版已基本实现#xff0c;包括基本配置读取、用例读取、用例执行、sql读取执行、前置数据准备、后置数据清理以及测试报告生成等#xff0c;环境独立运行、项目独立运行、用例独立运行、jenkins集… 经过一周多时间基于pythonpytestexcelallure框架的接口自动化测试初版已基本实现包括基本配置读取、用例读取、用例执行、sql读取执行、前置数据准备、后置数据清理以及测试报告生成等环境独立运行、项目独立运行、用例独立运行、jenkins集成、邮件发送暂未实现再后期版本会再次推出现在把整个框架设计思路和想法分享给大家来参考和借鉴。希望大家也能提供更好的思路和方法帮助我进行优化改进。 实战项目是三端交互的项目所以在设计思路上要考虑多项目如何交互目前只写了1个项目的其它2个项目都预留了位置后期直接添加就可以思路一样。
一、整个代码目录及介绍
common
request.py 封装post、get请求方法供所有地方调用
login.py 封装各项目、各种方式的登录方法供所有地方调用
readFile.py 封装读取yaml中配置文件、excel中测试用例方法供所有地方调用
execSql.py 封装sql操作增、删、改、查方法供所有地方调用
prefixSqlData.py 封装前置、后置公共sql供所有地方调用
assertion.py 封装断言方法供所有用例中调用
logs.py 封装日志方法供所有地方调用
config
sql.yaml 前置数据sql语句、后置清理sql语句等
test.yaml test环境数据库配置、接口域名、测试账号、登录接口数据等
uat.yaml uat环境数据库配置、接口域名、测试账号、登录接口数据等
testcase.xls 测试用例等
testcase
项目1 用例1、用例2
项目2 用例1、用例2
testcase.xls 接口测试用例等
conftest.py 放置了登录获取token供所有用例调用
run_all_case.py 执行所有测试用例并生成测试报告
logs
每天的日志数据
report
html 测试报告index.html 二、yaml文件基本配置
项目一:url: https://www.baidu.com/headers:Content-Type: application/jsonAuthorization: tokenaccount:a_account: 17900000000b_account: 18000000000c_account: 19900000000c_account1: 19900000001c_login:method: posturl: /user/loginparam:type: 7login_from: 7mobile: 18888888888code: 123456c_sms_code:method: posturl: /1.0/users/loginmysql:host: 127.0.0.1user: testpwd: testtest_db: user项目二:url: https://www.baidu.com/
三、yaml文件sql配置
项目一:查id:- select_list- select id from A.B where create_mobile{}查用户id:- select_list- select id from A.B where mobile{}查团队id:- select_list- select id from A.B where company_user_id(select id from A.B where mobile{})查C端用户id:- select_list- select user_id from A.B where mobile in({})解除用户:- update- update A.B set status2 where mobile{}项目二:查id:- select_list- select id from A.B where create_mobile{}查用户id:- select_list- select id from A.B where mobile{}查团队id:- select_list- select id from A.B where company_user_id(select id from A.B where mobile{})查C端用户id:- select_list- select user_id from A.B where mobile in({})解除用户:- update- update A.B set status2 where mobile{}
四、读取yaml文件、excel用例文件
#!/usr/bin/env python
# _*_coding:utf-8_*_
import yaml,os,sys,xlwt,xlrd
from common.logs import Logclass ReadFile(object):log Log()_instanceNonedef __new__(cls,*args,**kwargs):if cls._instance is None:cls._instancesuper().__new__(cls)return cls._instancedef __init__(self):self.excel_path os.path.join(os.path.dirname(os.path.dirname(__file__)), config/testcase.xls)self.yaml_path os.path.join(os.path.dirname(os.path.dirname(__file__)), config/test.yaml)self.sql_yaml_path os.path.join(os.path.dirname(os.path.dirname(__file__)), config/sql.yaml)def read_yaml(self,path_type):读yaml文件:return:try:if path_typeyaml_path:file_pathself.yaml_pathelif path_typesql_yaml_path:file_pathself.sql_yaml_pathwith open(file_path,r,encodingutf-8) as f:return yaml.load(f.read())except Exception as e:self.log.error(读yaml文件报错{}.format(e))def read_excel(self,sheet_name,function,casenameNone):读取excel:param sheet_name::param function::return:try:bookxlrd.open_workbook(self.excel_path)sheetbook.sheet_by_name(sheet_name)param[]for i in range(0,sheet.nrows):if casenameNone:if sheet.row_values(i)[0]function and sheet.row_values(i)[3]1:param.append(sheet.row_values(i))else:if sheet.row_values(i)[0]function and sheet.row_values(i)[1]casename and sheet.row_values(i)[3]1:param.append(sheet.row_values(i))return paramexcept Exception as e:self.log.error(读取excel报错{}.format(e))if __name__ __main__:testReadFile()print(test.read_excel(lxk,我的,全部页面))
五、用例模板如下
根据每个sheet存放不同项目的测试用例然后根据再根据sheet去读取对应项目模块的测试用例
Function模块、CaseName测试用例名、Type请求类型、Run是否执行、URL接口地址、Headers请求头、Param请求参数、SQL1、SQL2、SQL3测试中需用到的前置数据或后置数据、AssertType断言类型因为接口返回的响应数据可能会多种多样所以这里断言分了几种情况、Expect1预期结果1、Expect2预期结果2、Expect3预期结果3 六、request方法
#!/usr/bin/env python
# _*_coding:utf-8_*_
import requests,urllib3
from urllib3 import encode_multipart_formdata
from common.logs import Logclass RunMethod(object):requestlog Log()urllib3.disable_warnings()def post_main(self,url,data,header,fileNone):post请求:param url::param data::param header::param file::return:resNoneif file!None:resrequests.post(urlurl,jsondata,headersheader,verifyFalse)else:res requests.post(urlurl, jsondata,headersheader, filesfile, verifyFalse)return res.json()def get_main(self,url,header,paramNone):get请求:param url::param header::param param::return:resNoneif param!None:resrequests.get(urlurl,headersheader,verifyFalse)else:res requests.get(urlurl, headersheader, jsonparam,verifyFalse)return res.json()def run_main(self,method,url,header,dataNone,fileNone):被调用主request:param method::param url::param header::param data::param file::return:try:resNoneif methodpost or methodPOST or methodPost:resself.post_main(url,data,header,fileNone)elif methodget or methodGET or methodGet:resself.get_main(url,header,paramNone)else:return request传参错误return resexcept Exception as e:self.log.error(请求方法报错{}.farmat(e))
if __name__ __main__:print(111)
七、登录方法
#!/usr/bin/env python
# _*_coding:utf-8_*_
from common import request
from common.readFile import ReadFile
from common.logs import Logclass Login(object):登录log Log()request request.RunMethod()def __init__(self):self.yaml_data ReadFile().read_yaml(yaml_path)[lxk]self.header self.yaml_data[headers]self.url self.yaml_data[url]self.lxk_c_url self.yaml_data[c_login][url]self.lxk_c_method self.yaml_data[c_login][method]self.lxk_c_param self.yaml_data[c_login][param]def lxk_c_login(self,project,mobile):蓝薪卡C端登录:param project::param mobile::return:try:if projectlxk_c:self.lxk_c_param[mobile]mobileresultself.request.run_main(self.lxk_c_method, self.urlself.lxk_c_url, self.header, self.lxk_c_param)elif projectlxk_a:passelif projectlxk_b:passreturn resultexcept Exception as e:self.log.error(登录报错{}.format(e))if __name__ __main__:testLogin()print(test.lxk_c_login(lxk_c,18221124104))八、操作sql方法
#!/usr/bin/env python
# _*_coding:utf-8_*_
from common.readFile import ReadFile
import pymysql
import sys
from common.logs import Logclass ExecSql(object):执行sql语句类log Log()_instanceNonedef __new__(cls,*args,**kwargs):if cls._instance is None:cls._instancesuper().__new__(cls)return cls._instancedef __init__(self):初始化mysql配置:param platform_name:#self.sql_conf self._get_sql_conf(platform_name)self.sql_confNonedef _get_sql_conf(self, project):获取mysql配置:param platform_name::return:try:return ReadFile().read_yaml(yaml_path)[project][mysql]except:self.log.error(找不到对应项目{0}.format(project))def connect_db(self):连接mysql:return:host self.sql_conf[host]user self.sql_conf[user]pwd self.sql_conf[pwd]test_db self.sql_conf[test_db]try:self.conn pymysql.connect(hosthost, useruser, passwordpwd, dbtest_db, port3306, charsetutf8)except Exception as e:self.log.error(连接mysql失败{0}.format(e))def get_cursor(self):获取游标:return:self.cursorself.conn.cursor()return self.cursordef exec_sql(self,project,sql_type,sql):执行sql语句:param sql_type::param sql::return:self.sql_conf self._get_sql_conf(project)try:if sql_type select_one:self.connect_db()cursor self.get_cursor()cursor.execute(sql)result cursor.fetchone()elif sql_type select_list:self.connect_db()cursor self.get_cursor()cursor.execute(sql)result cursor.fetchall()elif sql_type update or sql_type del or sql_type insert:self.connect_db()result self.get_cursor().execute(sql)self.conn.commit()self.cursor.close()self.conn.close()return resultexcept Exception as e:self.log.error(执行sql语句报错{0}.format(e))if __name__ __main__:test ExecSql()atest.exec_sql(lxk,select_list,sql)print(aaa)
九、日志方法
#!/usr/bin/env python
# _*_coding:utf-8 _*_
import os, time, logging
log_pathos.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), logs)
if not os.path.exists(log_path): os.mkdir(log_path)class Log(object):log日志类def __init__(self):self.logname os.path.join(log_path, %s.log % time.strftime(%Y_%m_%d))self.logger logging.getLogger()self.logger.setLevel(logging.DEBUG)self.formatter logging.Formatter([%(asctime)s]-%(filename)s]-%(levelname)s:%(message)s)def __console(self, level, message):fhlogging.FileHandler(self.logname, a, utf-8)fh.setLevel(logging.DEBUG)fh.setFormatter(self.formatter)self.logger.addHandler(fh)ch logging.StreamHandler()ch.setLevel(logging.INFO)ch.setFormatter(self.formatter)self.logger.addHandler(ch)if level info:self.logger.info(message)elif level debug:self.logger.debug(message)elif level warning:self.logger.warning(message)elif level error:self.logger.error(message)self.logger.removeHandler(ch)self.logger.removeHandler(fh)fh.close()def debug(self, message):self.__console(debug, message)def info(self, message):self.__console(info, message)def warning(self, message):self.__console(warning, message)def error(self, message):self.__console(error, message)if __name__ __main__:log Log()log.info(---测试---)
十、断言方法
#!/usr/bin/env python
# _*_coding:utf-8_*_
from common.execSql import ExecSql
from common.logs import Logclass Assertion(object):logLog()sql_values_list []response_values []def __init__(self):self.testExecSql().exec_sqldef get_sql_data(self,project,sql_type,sql):查询sql数据组合list:param project::param sql_type::param sql::return:try:sql_valuesself.test(project,sql_type,sql)for i in sql_values:for j in i:self.sql_values_list.append(j)except Exception as e:self.log.error(查询sql数据组合list报错{}.format(e))def get_response_data(self,response_data, keys[]):获取接口响应数据组合list:param response_data::param keys::return:try:if isinstance(response_data, list):for value in response_data:if isinstance(value, list) or isinstance(value, dict):self.get_response_data(value, keys)elif isinstance(response_data, dict):for i, j in sorted(response_data.items()):if i in keys:self.response_values.append(j)else:self.get_response_data(j, keys)else:passexcept Exception as e:self.log.error(获取接口响应数据组合list报错{}.format(e))def asser(self,function,casename,expect,response_data,assert_typeNone):断言:param assert_type::param expect::param response_data::return:try:if assert_typetype1:assert self.sql_values_listself.response_valuesself.log.info(查询sql数据组合list为{}.format(self.sql_values_list))self.log.info(接口响应数据组合list为{}.format(self.response_values))assert eval(expect)[code] response_data[code]assert eval(expect)[msg] response_data[msg]self.log.info({}——{}【PASS】.format(function,casename))except Exception as e:self.log.error({}——{}【PASS】{}.format(function,casename,e))if __name__ __main__:# sqlsql# testAssertion()# test.get_sql_data(self,project,sql_type,sql)self.log.error(查询sql数据组合list报错{}.format(e))
十一、conftest登录获取token
#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytest,os,yaml,requests
from common.readFile import ReadFile
from common.login import Loginyaml_dataReadFile().read_yaml(yaml_path)pytest.fixture(scopesession)
def get_lxk_c_headers():登录获取token更新headers:return:headersyaml_data[lxk][headers]tokenLogin().lxk_c_login(lxk_c,yaml_data[lxk][account][c_account])[data][token]headers[Authorization]tokenreturn headers
十二、测试用例方法
#!/usr/bin/env python
# _*_coding:utf-8_*_import pytest
from common.readFile import ReadFile
from common.request import RunMethod
from common.assertion import Assertion
from common.execSql import ExecSql
from common.prefixSqlData import MakeSqlData
import alluredata ReadFile().read_excel(lxk, 我的报名)pytest.mark.parametrize(function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3,data)
class Test(object):我的报名request RunMethod().run_mainassertion Assertion()exec_sql ExecSql().exec_sqlyaml_data ReadFile().read_yaml(yaml_path)[lxk]sql_yaml_data ReadFile().read_yaml(sql_yaml_path)[lxk]prefix_sql_data MakeSqlData(lxk).make_sql_datadef setup_class(self):数据初始化:return:prefix_dataself.prefix_sql_data(self.yaml_data[account][b_account], self.yaml_data[account][c_account])company_id self.exec_sql(lxk, self.sql_yaml_data[查企业id][0], self.sql_yaml_data[查企业id][1].format(self.yaml_data[account][b_account]))[0][0]task_id self.exec_sql(lxk, self.sql_yaml_data[查任务id][0], self.sql_yaml_data[查任务id][1].format(self.yaml_data[account][b_account]))[0][0]self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],1))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],2))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],3))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],4))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],5))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account],7))self.exec_sql(lxk, self.sql_yaml_data[报名任务][0], self.sql_yaml_data[报名任务][1].format(prefix_data[user_id], task_id, company_id,self.yaml_data[account][c_account], 8))def teardown_class(self):数据清理:return:self.exec_sql(lxk, self.sql_yaml_data[删除已报名任务][0], self.sql_yaml_data[删除已报名任务][1].format(self.yaml_data[account][c_account]))self.exec_sql(lxk, self.sql_yaml_data[解除用户团队][0], self.sql_yaml_data[解除用户团队][1].format(self.yaml_data[account][c_account]))#allure.feature(蓝薪卡)allure.story(lxk_我的报名)def test_apply_task(self,get_lxk_c_headers,function,casename,type,run,url,hearders,param,sql1,sql2,sql3,asserttype,expect1,expect2,expect3):我的报名:param get_lxk_c_headers::param function::param casename::param type::param run::param url::param hearders::param param::param sql1::param sql2::param sql3::param asserttype::param expect1::param expect2::param expect3::return:response_data self.request(type,self.yaml_data[url]url,get_lxk_c_headers,eval(param))self.assertion.get_sql_data(lxk,eval(sql1)[0],eval(sql1)[1].format(self.yaml_data[account][c_account]))self.assertion.get_response_data(response_data,eval(expect2))self.assertion.asser(function,casename,expect1,response_data,asserttype)if __name__ __main__:pytest.main([-s, test_001_applyTask.py])
十三、run_all_case主程序执行入口
#!/usr/bin/env python
# _*_coding:utf-8_*_
import pytest,os,allure
if __name__ __main__:pytest.main([-s,])#生成测试报告jsonpytest.main([-s, -q, --alluredir, C:/Users/wangli/PycharmProjects/PytestAutomation/report/result])#将测试报告转为html格式splitallure generate C:/Users/wangli/PycharmProjects/PytestAutomation/report/result -o C:/Users/wangli/PycharmProjects/PytestAutomation/report/html --cleanos.system(cd C:/Users/wangli/PycharmProjects/PytestAutomation/report)os.system(split)print(split)十四、测试报告如下