基于Pytest+Requests+Allure实现接口自动化测试

一、整体结构

框架组成:pytest+requests+allure

设计模式:

关键字驱动

项目结构:

 
  1. 工具层:api_keyword/

  2. 参数层:params/

  3. 用例层:case/

  4. 数据驱动:data_driver/

  5. 数据层:data/

  6. 逻辑层:logic/

二、具体步骤及代码

1、工具层

将get、post等常用行为进行二次封装。

代码(api_key.py)如下:

 
  1. import allure

  2. import json

  3. import jsonpath

  4. import requests

  5. # 定义一个关键字类

  6. class ApiKey:

  7. # 将get请求行为进行封装

  8. @allure.step("发送get请求")

  9. def get(self, url, params=None, **kwargs):

  10. return requests.get(url=url, params=params, **kwargs)

  11. # 将post请求行为进行封装

  12. @allure.step("发送post请求")

  13. def post(self, url, data=None, **kwargs):

  14. return requests.post(url=url, data=data, **kwargs)

  15. # 由于接口之间可能相互关联,因此下一个接口需要上一个接口的某个返回值,此处采用jsonpath对上一个接口返回的值进行定位并取值

  16. @allure.step("获取返回结果字典值")

  17. def get_text(self, data, key):

  18. # json数据转换为字典

  19. json_data = json.loads(data)

  20. # jsonpath取值

  21. value = jsonpath.jsonpath(json_data, '$..{0}'.format(key))

  22. return value[0]

其中引用allure.step()装饰器进行步骤详细描述,使测试报告更加详细。

使用jsonpath对接口的返回值进行取值。

2、数据层

数据采用yaml文件。

代码(user.yaml)如下:

 
  1. -

  2. user:

  3. username: admin

  4. password: '123456'

  5. msg: success

  6. title: 输入正确账号、密码,登录成功

  7. -

  8. user:

  9. username: admin1

  10. password: '1234561'

  11. msg: 用户名或密码错误

  12. title: 输入错误账号1、密码1,登录失败

  13. -

  14. user:

  15. username: admin2

  16. password: '1234562'

  17. msg: 用户名或密码错误

  18. title: 输入错误账号2、密码2,登录失败

其中title是为了在用例进行时动态获取参数生成标题。

3、数据驱动层

对数据进行读写。

代码(yaml.driver.py)如下:

 
  1. import yaml

  2. def load_yaml(path):

  3. file = open(path, 'r', encoding='utf-8')

  4. data = yaml.load(file, Loader=yaml.FullLoader)

  5. return data

4、参数层

参数层存放公共使用的参数,在使用时对其进行调用。

代码(allParams.py)如下:

 
  1. '''python

  2. 规则:

  3. 全局变量使用大写字母表示

  4. '''

  5. # 地址

  6. URL = 'http://39.98.138.157:'

  7. # 端口

  8. PORT = '5000'

5、逻辑层

用例一:进行登录的接口请求,此处登录请求在yaml文件里设置了三组不同的数据进行请求。

用例二:进行个人查询的接口请求,此处需要用到登录接口返回的token值。

用例三、进行添加商品到购物车的接口请求,此处需要用到登录接口返回的token值以及个人查询接口返回的openid、userid值

用例四、进行下单的接口请求,此处需要用到登录接口返回的token值以及个人查询接口返回的openid、userid、cartid值

注意:由于多数接口需要用到登录接口返回的token值,因此封装一个conftest.py定义项目级前置fixture,在整个项目只执行一次,可以在各个用例中进行调用(其他共用参数也可以采取类似前置定义)。同时由于此处定义的项目级fixture,因此可以将初始化工具类ak = ApiKey()也放入其中。
代码(conftest.py)如下:

 
  1. from random import random

  2. import allure

  3. import pytest

  4. from pytest_demo_2.api_keyword.api_key import ApiKey

  5. from pytest_demo_2.params.allParams import *

  6. def pytest_collection_modifyitems(items):

  7. """

  8. 测试用例收集完成时,将收集到的item的name和nodeid的中文显示在控制台上

  9. """

  10. for item in items:

  11. item.name = item.name.encode("utf-8").decode("unicode_escape")

  12. item._nodeid = item.nodeid.encode("utf-8").decode("unicode_escape")

  13. # 项目级fix,整个项目只初始化一次

  14. @pytest.fixture(scope='session')

  15. def token_fix():

  16. # 初始化工具类`在这里插入代码片`

  17. ak = ApiKey()

  18. with allure.step("发送登录接口请求,并获取token,整个项目只生成一次"):

  19. # 请求接口

  20. # url = 'http://39.98.138.157:5000/api/login'

  21. url = URL + PORT + '/api/login'

  22. # 请求参数

  23. userInfo = {

  24. 'username': 'admin',

  25. 'password': '123456'

  26. }

  27. # post请求

  28. res = ak.post(url=url, json=userInfo)

  29. # 获取token

  30. token = ak.get_text(res.text, 'token')

  31. # 验证代码,验证token只生成一次

  32. token_random = random()

  33. return ak, token, res, token_random

其中也包含了防止中文乱码,加入了pytest_collection_modifyitems(函数)。

设置好conftest后,就可以应用在逻辑层里面了。

代码(shopingApi.py)如下:

 
  1. import pytest

  2. import allure

  3. from pytest_demo_2.api_keyword.api_key import ApiKey

  4. from pytest_demo_2.params.allParams import *

  5. class ApiCase():

  6. # 登录逻辑

  7. def params_login(self, userdata):

  8. # 动态获取参数生成标题

  9. allure.dynamic.title(userdata['title'])

  10. # 初始化工具类

  11. ak = ApiKey()

  12. # 请求接口

  13. url = URL + PORT + '/api/login'

  14. # 请求参数

  15. userInfo = {

  16. 'username': userdata['user']['username'],

  17. 'password': userdata['user']['password']

  18. }

  19. res = ak.post(url=url, json=userInfo)

  20. with allure.step("接口返回信息校验及打印"):

  21. print("/api/login登录接口请求响应信息")

  22. print(res.text)

  23. # 获取响应结果

  24. msg = ak.get_text(res.text, 'msg')

  25. print(msg)

  26. # 断言

  27. assert msg == userdata['msg']

  28. def params_getuserinfo(self, token_fix):

  29. # 从fix中获取预置的工具类和token,所有返回值都需要接收

  30. ak, token, res, token_random01 = token_fix

  31. with allure.step("发送个人查询接口请求"):

  32. url = URL + PORT + '/api/getuserinfo'

  33. headers = {

  34. 'token': token

  35. }

  36. res1 = ak.get(url=url, headers=headers)

  37. with allure.step("接口返回信息校验及打印"):

  38. print("/api/getuserinfo个人用户查询接口请求响应信息")

  39. print(res1.text)

  40. # print("验证的random值,测试用")

  41. # print(token_random01)

  42. name = ak.get_text(res1.text, 'nikename')

  43. # 断言

  44. assert "风清扬" == name

  45. return res1

  46. def params_addcart(self, token_fix):

  47. # 从fix中获取预置的工具类和token

  48. # 所有返回都要获取,不然会报错

  49. ak, token, res, token_random01 = token_fix

  50. with allure.step("调用getuserinfo接口获取返回信息"):

  51. res1 = self.params_getuserinfo(token_fix)

  52. with allure.step("发送添加商品到购物车请求"):

  53. # 添加商品到购物车,基于token、userid、openid、productid

  54. url = URL + PORT + '/api/addcart'

  55. hd = {

  56. "token": token

  57. }

  58. data = {

  59. "userid": ak.get_text(res1.text, 'userid'),

  60. "openid": ak.get_text(res1.text, 'openid'),

  61. "productid": 8888

  62. }

  63. # 发送请求

  64. res2 = ak.post(url=url, headers=hd, json=data)

  65. with allure.step("接口返回信息校验及打印"):

  66. print("/api/addcart添加商品到购物车请求响应信息")

  67. print(res2.text)

  68. # print("验证的random值,测试用")

  69. # print(token_random01)

  70. result = ak.get_text(res2.text, 'result')

  71. assert 'success' == result

  72. return res2

  73. def params_createorder(self, token_fix):

  74. ak, token, res, token_random01 = token_fix

  75. with allure.step("调用addcart接口获取返回信息"):

  76. res1 = self.params_addcart(token_fix)

  77. with allure.step("发送下单请求"):

  78. url = URL + PORT + '/api/createorder'

  79. # 从项目级fix中获取token

  80. hd = {

  81. "token": token

  82. }

  83. # 从添加商品到购物车接口中获取userid,openid,cartid

  84. data = {

  85. "userid": ak.get_text(res1.text, 'userid'),

  86. "openid": ak.get_text(res1.text, 'openid'),

  87. "productid": 8888,

  88. "cartid": ak.get_text(res1.text, 'cartid')

  89. }

  90. res2 = ak.post(url=url, headers=hd, json=data)

  91. with allure.step("接口返回信息校验及打印"):

  92. print("/api/createorder下单请求响应信息")

  93. print(res2.text)

  94. # print("验证的random值,测试用")

  95. # print(token_random01)

  96. result = ak.get_text(res1.text, 'result')

  97. assert 'success' == result

6、用例层

调用逻辑层进行用例管理和数据传输。

代码(test_Tree.py)如下:

  1. import allure

  2. import pytest

  3. from pytest_demo_2.data_driver import yaml_driver

  4. from pytest_demo_2.logic.shopingApi import ApiCase

  5. @allure.epic("shopXo电商平台接口-接口测试")

  6. class TestTree():

  7. # 初始化用例库

  8. actions1 = ApiCase()

  9. @allure.feature("01.登陆")

  10. @allure.story("02.一般场景")

  11. @pytest.mark.parametrize('userdata', yaml_driver.load_yaml('./data/user.yaml'))

  12. def test_case01(self, userdata):

  13. self.actions1.params_login(userdata)

  14. @allure.feature("02.个人查询")

  15. @allure.story("01.典型场景")

  16. @allure.title("个人查询")

  17. def test_case02(self, token_fix):

  18. self.actions1.params_getuserinfo(token_fix)

  19. @allure.feature("03.添加商品到购物车")

  20. @allure.story("01.典型场景")

  21. @allure.title("添加商品到购物车")

  22. def test_case03(self, token_fix):

  23. self.actions1.params_addcart(token_fix)

  24. @allure.feature("04.下单")

  25. @allure.story("01.典型场景")

  26. @allure.title("下单")

  27. def test_case04(self, token_fix):

  28. self.actions1.params_createorder(token_fix)

7、运行

代码(main_run.py)如下:

 
  1. import os

  2. import pytest

  3. def run():

  4. pytest.main(['-v', './case/test_Tree.py',

  5. '--alluredir', './result', '--clean-alluredir'])

  6. os.system('allure serve result')

  7. # os.system('allure generate ./result/ -o ./report_allure/ --clean')

  8. if __name__ == '__main__':

  9. run()

8、结果

在这里插入图片描述

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

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值