从0到1框架搭建,Python+Pytest+Allure+Git+Jenkins接口自动化框架(超细整理)

前言

接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为HTTP,RPC,Webservice,Dubbo,RESTful等类型。

接口测试流程
1、需求评审,熟悉业务和需求
2、开发提供接口文档
3、编写接口测试用例
4、用例评审
5、提测后开始测试
6、提交测试报告

两种常见的 HTTP 请求方法:GET 和 POST

框架是一套基于Python+Pytest+Requests+Allure+Jenkins而设计的数据驱动接口自动化测试的框架。

技术栈:
Python、Pytest、Requests、Pactverity、Excel、Json、Mysql、Allure、Logbook、Git、Jenkins

框架结构图:

项目功能:
Python+Pytest+Allure+Jenkins接口自动化框架,实现Excel或Json维护测试用例,支持数据库操作,利用封装的请求基类调取相应的测试用例接口,获取配置文件中的环境地址与环境变量,

结合Pytest进行单元测试,使用LogBook进行记录日志,并生成allure测试报告,最后进行Jenkins集成项目实现集成部署,并发送测试报告邮件。

工具类封装

1、日志模块
项目中的log日志是logbook进行日志记录的,方便测试开发调试时进行排错纠正或修复优化。日志可选择是否打印在屏幕上即运行时是否在终端输出打印。日志格式输出可调整。

handle_log.py部分源码

 

def log_type(record, handler):

log = "[{date}] [{level}] [{filename}] [{func_name}] [{lineno}] {msg}".format(

date=record.time, # 日志时间

level=record.level_name, # 日志等级

filename=os.path.split(record.filename)[-1], # 文件名

func_name=record.func_name, # 函数名

lineno=record.lineno, # 行号

msg=record.message # 日志内容

)

return log

# 日志存放路径

LOG_DIR = BasePath + '/log'

print(LOG_DIR)

if not os.path.exists(LOG_DIR):

os.makedirs(LOG_DIR)

# 日志打印到屏幕

log_std = ColorizedStderrHandler(bubble=True)

log_std.formatter = log_type

# 日志打印到文件

log_file = TimedRotatingFileHandler(

os.path.join(LOG_DIR, '%s.log' % 'log'), date_format='%Y-%m-%d', bubble=True, encoding='utf-8')

log_file.formatter = log_type


# 脚本日志

run_log = Logger("global_log")

def init_logger():

logbook.set_datetime_format("local")

run_log.handlers = []

run_log.handlers.append(log_file)

run_log.handlers.append(log_std)

return ""

打印在终端的日志,如下图所示。

同时运行项目后,会在项目文件log中自动生成一个以当天日期命名的log文件。点击log日志文件可查看日志详情即项目运行时所记录的日志或报错日志。如下图所示。

2、配置文件模块
项目中涉及到一些配置文件如username、password或环境变量时,我们可通过配置文件来获取配置值。通过配置文件中key与value的定义来确定获取配置文件的值。

handle_init.py部分源码

 

class HandleInit:

# 读取配置文件

def load_ini(self):

file_path = BasePath + "/config/config.ini"

cf = configparser.ConfigParser()

cf.read(file_path, encoding='UTF-8')

return cf


# 获取ini里面对应key的value

def get_value(self, key, node=None):

if node == None:

node = 'Test'

cf = self.load_ini()

try:

data = cf.get(node, key)

logger.info('获取配置文件的值,node:{},key:{}, data:{}'.format(node, key, data))

except Exception:

logger.exception('没有获取到对应的值,node:{},key:{}'.format(node, key))

data = None

return data

获取配置文件中的值日志如下图所示。

B3

3、接口请求封装
获取相关测试用例及接口用例配置,记录请求相关参数的日志,定义Allure测试报告的步骤。

handle_apirequest.py部分代码

 

class ApiRequest:

def api_request(self, base_url, test_case_data, case_data):

get_name = None

get_url = None

get_method = None

get_headers = None

get_cookies = None

get_case_name = None

get_case_params = None

response_data = None

try:

get_name = test_case_data['config']['name']

get_url = base_url + test_case_data['config']['url']

get_method = test_case_data['config']['method']

get_headers = test_case_data['config']['headers']

get_cookies = test_case_data['config']['cookies']

except Exception as e:

logger.exception('获取用例基本信息失败,{}'.format(e))

try:

get_case_name = case_data['name']

get_case_params = case_data['params']

except Exception as e:

logger.exception('获取测试用例信息失败,{}'.format(e))

with allure.step("请求接口:%s,请求地址:%s,请求方法:%s,请求头:%s,请求Cookies:%s" % (

get_name, get_url, get_method, get_headers, get_cookies)):

allure.attach("接口用例描述:", "{0}".format(get_case_name))

allure.attach("接口用例请求参数:", "{0}".format(get_case_params))

logger.info(

'请求接口名:%r,请求地址:%r,请求方法:%r,请求头:%r,请求Cookies:%r' %\


(get_name, get_url, get_method, get_headers, get_cookies))

logger.info('请求接口名:%r,请求接口用例名:%r,接口用例请求参数:%r' %\


(get_name, get_case_name, get_case_params))

try:

response_data = baseRequest.run_main(get_method, get_url, get_case_params, get_headers)

except Exception as e:

logger.exception('用例请求返回失败,{}'.format(e))

logger.info('请求接口名:%r,请求接口用例名:%r,返回参数:%r' % (get_name, get_case_name, response_data.json()))

return response_data

4、Excel数据处理-测试用例

测试用例中维护在Excel文件中,类中定义如何获取Excel中的相关数据(如获取某个单元格的内容,获取单元格的行数,以及将数据写入Excel中等操作)。

handle_exceldata.py部分源码

 

class OperationExcel:

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 = ''

self.sheet_id = 0

self.data = self.get_data()


# 获取sheets的内容

def get_data(self):

data = xlrd.open_workbook(self.file_name)

tables = data.sheets()[self.sheet_id]

return tables


# 获取单元格的行数

def get_lines(self):

tables = self.data

return tables.nrows


# 获取某一个单元格的内容

def get_cell_value(self, row, col):

return self.data.cell_value(row, col)

5、JSON数据处理-测试用例

 

{

"config":{

"name":"post接口名",

"url":"/langdetect",

"method":"POST",

"headers":{

"Content-Type":"application/json"

},

"cookies":{


}

},

"testcase":[

{

"name":"测试用例1",

"params":{

"query":"测试"

},

"validate":[

{

"check":"status_code",

"comparator":"eq",

"expect":"200"

}

]

},

{

"name":"测试用例2",

"params":{

"query":"python"

},

"validate":[

{

"check":"msg",

"comparator":"eq",

"expect":"success"

}

]

}

]

}

获取Json文件中里具体字段的值。
handle.json.py部分源码

 

class HandleJson:

# 读取json文件

def load_json(self, file_name):

if file_name == None:

file_path = ""

else:

file_path = file_name

try:

with open(file_path, encoding='UTF-8') as f:

data = json.load(f)

return data

except Exception:

print("未找到json文件")

return {}


# 读取json文件里具体的字段值

def getJson_value(self, key, file_name):

if file_name == None:

return ""

jsonData = self.load_json(file_name)

if key == None:

getJsonValue = ""

else:

getJsonValue = jsonData.get(key)

return getJsonValue

基类封装

接口支持Get、Post请求,调用requests请求来实现接口的调用与返回。接口参数包括,接口地址、接口请求参数、cookie参数、header参数。

 

class BaseRequest:


def send_get(self, url, data, header=None, cookie=None):

"""

Requests发送Get请求

:param url:请求地址

:param data:Get请求参数

:param cookie:cookie参数

:param header:header参数

"""

response = requests.get(url=url, params=data, cookies=cookie, headers=header)

return response


def send_post(self, url, data, header=None, cookie=None):

"""

Requests发送Post请求

:param url:请求地址

:param data:Post请求参数

:param data:Post请求参数

:param cookie:cookie参数

:param header:header参数

"""

response = requests.post(url=url, json=data, cookies=cookie, headers=header)

return response


# 主函数调用


def run_main(self, method, url, data, header, cookie=None):

try:

result = ''

if method.upper() == 'GET':

result = self.send_get(url, data, header, cookie)

elif method.upper() == 'POST':

result = self.send_post(url, data, header, cookie)

return result

except Exception as e:

logger.exception('请求主函数调用失败:{}'.format(e))

测试用例编写

引用Pytest来进行接口的单元测试,通过JSON中多个测试用例来做为参数化数据驱动。结合Allure制定相应接口的测试报告。在接口返回断言之前,我们先进行该接口的契约测试,

我们采用的是Pactverity的全量契约校验测试。当契约测试通过时,我们再进行返回参数的相关校验测试。

test_getRequestJson.py部分源码

 

@allure.feature('测试GET请求模块')

class TestRequestOne():

@allure.title('测试标题')

@allure.testcase('测试地址:https://www.imooc.com')

@pytest.mark.parametrize('case_data', testCaseData['testcase'])

def test_requestOne(self, case_data):

try:

api_response = apiRequest.api_request(baseurl, testCaseData, case_data)

api_response_data = api_response.json()

# pactverity——全量契约校验

config_contract_format = Like({

"msg": "成功",

"result": 0,

"data": EachLike({

"word": Like("testng")

})

})

mPactVerify = PactVerify(config_contract_format)

try:

mPactVerify.verify(api_response_data)

logger.info(

'verify_result:{},verify_info:{}'.format(mPactVerify.verify_result, mPactVerify.verify_info))

assert mPactVerify.verify_result == True

except Exception:

err_msg = '契约校验错误'

logger.exception('测试用例契约校验失败,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,

mPactVerify.verify_info))

try:

for case_validate in case_data['validate']:

logger.info('断言期望相关参数:check:{},comparator:{},expect:{}'.format(case_validate['check'],

case_validate['comparator'],

case_validate['expect']))

comparatorsTest.comparators_Assert(api_response, case_validate['check'],

case_validate['comparator'], case_validate['expect'])

logger.info('测试用例断言成功')

except Exception as e:

logger.exception('测试用例断言失败')

except Exception as e:

logger.exception('测试用例请求失败,原因:{}'.format(e))

主运行:

运用Pytest和Allure的特性,命令行运行测试用例文件夹,并生成对应的allure测试报告。


if __name__ == "__main__":

pytest.main(['-s', '-v', 'test_case/testRequest/', '-q', '--alluredir', 'reports'])

Alluer2 测试报告

当我们运行主函数时,并生成对应的测试用例报告时,我们可以看到在该文件夹中会生成对应的json文件的测试报告。

reports是json格式测试报告存放的目录位置,allure_reports是html测试报告文件生成的目录位置。allure命令如下。

allure generate reports -o allure_result/

项目根目录下的allure_reports文件,存放的是allure生成的测试报告。可看出文件下有一个HTML文件,可通过Python的编辑器Pycharm来打开该HTML文件(测试报告),或可通过allure命令来打开该HTML。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:【文末小卡片领取】

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
搭建一个接口自动化测试框架可以使用以下工具和技术: 1. Python:作为主要开发语言,可以使用Python来编写测试脚本和测试用例。 2. Pytest:一款功能强大的Python测试框架,可以用于编写和运行测试用例,并提供丰富的断言和报告功能。 3. Allure:一个开源的测试报告生成工具,可以生成美观且易于理解的测试报告,支持多种语言和框架。 4. Git:版本控制工具,用于管理和同步测试代码。 5. Jenkins:一个持续集成和持续交付工具,可以自动化运行测试用例并生成测试报告。 6. Docker:容器化平台,可以用于创建和管理测试环境,提供一致的运行环境。 下面是搭建接口自动化测试框架的步骤: Step 1: 创建项目结构 在本地创建一个目录作为项目根目录,然后在根目录下创建以下子目录: - `tests`:存放测试脚本和测试用例; - `reports`:存放测试报告; - `config`:存放配置文件; - `utils`:存放一些工具类和函数。 Step 2: 编写测试用例 在`tests`目录下编写测试脚本和测试用例。可以使用Pytest来组织和执行测试用例,使用断言来验证测试结果。 Step 3: 配置Allure报告 在`config`目录下创建一个`pytest.ini`文件,配置Allure报告的相关参数,例如报告保存路径、报告标题等。 Step 4: 运行测试用例 使用Pytest运行测试用例,并生成Allure报告。可以使用命令行或者集成到Jenkins中进行自动化执行。 Step 5: 集成GitJenkins 将项目代码托管到Git仓库中,并在Jenkins中配置相关任务,使其在代码提交后自动触发测试用例的运行和报告的生成。 Step 6: 创建Docker镜像(可选) 使用Docker将测试环境打包成镜像,方便部署和维护。 一些可能出现的问题和解决方法: 1. 安装依赖:在搭建过程中,可能会遇到安装依赖包的问题。可以使用pip来安装所需的Python包,并注意版本兼容性。 2. 配置问题:在配置AllureJenkins时,可能会遇到配置不正确或缺少必要参数的问题。可以参考官方文档或者搜索解决方案来解决这些问题。 3. 报告生成失败:如果生成Allure报告失败,可以检查相关依赖是否安装正确,以及路径和权限是否设置正确。 4. 测试环境问题:如果测试用例在不同环境中运行时出现问题,可以考虑使用Docker来创建一致的测试环境,或者在测试用例中添加环境适配代码。 相关问题: 1. 除了Allure,还有哪些常用的测试报告生成工具? 2. 如何在Pytest中使用断言来验证测试结果? 3. 如何在Jenkins中配置任务来触发自动化测试? 4. 除了接口自动化测试,还有哪些类型的自动化测试可以使用Python实现?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值