• 接口自动化测试_L3


    目录:

    1. 整体结构响应断言
      1. 响应信息数据极为庞大,针对于“大响应数据”如何断言
      2. JSONSchema 简介
      3. JSONSchema 整体结构响应断言
      4. JSONSchema 的生成
      5. JSONSchema 的生成效果
      6. 界面工具生成
      7. 第三方库生成(Python)
      8. JSONSchema 验证(Python)
      9. JSONSchema 二次封装
    2. 数据库操作与断言
      1. 接口测试响应验证
      2. 接口测试数据清理
      3. 数据库操作注意事项
      4. 接口自动化测试常用的数据库操作
      5. 数据库信息
      6. 数据库封装(Python)
      7. 查询数据与数据库断言(Python)
    3. 接口鉴权的多种情况与解决方案
      1. 接口鉴权是什么?
      2. 接口鉴权通用的解决方案
      3. 后端接口鉴权常用方法
      4. cookie 鉴权
      5. token 鉴权
      6. auth 鉴权(了解即可)
      7. auth 鉴权-代码示例
    4. 电子商城接口自动化测试实战
      1. 电子商城需求分析
      2. 商城业务场景
      3. 研发技术评审
      4. 接口测试用例设计思路
      5. 添加购物车流程脚本编写
      6. 脚本优化-参数化(Python)
      7. 脚本优化-添加日志(Python)
      8. 脚本优化-数据清理(Python)
      9. 脚本优化-报告展示
      10. 项目地址:

    1.整体结构响应断言

    响应信息数据极为庞大,针对于“大响应数据”如何断言
    • 针对主要且少量的业务字段断言。
    • 其他字段不做数据正确性断言,只做类型与整体结构的校验。
    • 与前面的版本进行 diff,对比差异化的地方。
    JSONSchema 简介
    • 使用 JSON 格式编写的
    • 可以用来定义校验 JSON 数据的结构
    • 可以用来校验 JSON 数据的一致性
    • 可以用来校验 API 接口请求和响应
     JSONSchema 整体结构响应断言
    1. 预先生成对应结构的 Schema。
    2. 将实际获取到的响应与生成的 Schema 进行对比。
    JSONSchema 的生成
    • 通过界面工具生成。
    • 通过第三方库生成。
    • 通过命令行工具生成。
    JSONSchema 的生成效果
    1. // # 预期的 JSON 文档结构
    2. {
    3. "name": "LiMing",
    4. "Courses": ["Mock", "Docker"]
    5. }
    1. // jsonschema
    2. {
    3. "$schema": "http://json-schema.org/draft-06/schema#",
    4. "$ref": "#/definitions/Welcome",
    5. "definitions": {
    6. "Welcome": {
    7. "type": "object",
    8. "additionalProperties": false,
    9. "properties": {
    10. "name": {
    11. "type": "string"
    12. },
    13. "Courses": {
    14. "type": "array",
    15. "items": {
    16. "type": "string"
    17. }
    18. }
    19. },
    20. "required": ["Courses", "name"],
    21. "title": "Welcome"
    22. }
    23. }
    24. }
    界面工具生成
    • 复制 JSON 数据
    • 粘贴到在线生成工具中
    • 自动生成 JSON Schema 数据

    JSON Schema 在线生成工具:https://app.quicktype.io 

    第三方库生成(Python)
    1. 安装:pip install genson
    2. 调用方法生成对应的 JSONSchema 数据结构。
    1. from genson import SchemaBuilder
    2. def gernerate_jsonschema(obj):
    3. builder = SchemaBuilder()
    4. builder.add_object(obj)
    5. return builder.to_schema()
    6. def test_generate_jsonschema():
    7. print(gernerate_jsonschema({"name": 1}))

    运行结果:

     

     JSONSchema 验证(Python)
    1. 安装:pip install jsonschema
    2. 调用 validate() 进行验证。
    1. def schema_validate(obj, schema):
    2. '''
    3. 对比 python 对象与生成的 JSONSchame 的结构是否一致
    4. '''
    5. try:
    6. validate(instance=obj, schema=schema)
    7. return True
    8. except Exception as e:
    9. return False

     代码示例:

    1. import json
    2. from genson import SchemaBuilder
    3. from jsonschema.validators import validate
    4. def gernerate_jsonschema(obj):
    5. builder = SchemaBuilder()
    6. builder.add_object(obj)
    7. return builder.to_schema()
    8. def test_generate_jsonschema():
    9. print(gernerate_jsonschema({"name": 1}))
    10. def gernerate_jsonschema_file(obj, file_path):
    11. res = gernerate_jsonschema(obj)
    12. with open(file_path, 'w') as f:
    13. json.dump(res, f)
    14. def test_generate_jsonschema_file():
    15. gernerate_jsonschema_file({"name": 1}, "./datas/validate.json")
    16. def schema_validate(obj, schema):
    17. try:
    18. validate(instance=obj, schema=schema)
    19. return True
    20. except Exception as e:
    21. return False
    22. def test_schema_validate():
    23. with open("./datas/validate.json", 'r') as f:
    24. res = json.load(f)
    25. schema_validate({"name": 1}, res)
     JSONSchema 二次封装
    • 生成JSONSchema
    • 验证JSONSchema
    1. class JSONSchemaUtils:
    2. @classmethod
    3. def generate_schema(cls, obj):
    4. # 实例化jsonschem
    5. builder = SchemaBuilder()
    6. # 传入被转换的对象
    7. builder.add_object(obj)
    8. # 转换成 schema 数据
    9. return builder.to_schema()
    10. @classmethod
    11. def schema_validate(cls, obj, schema):
    12. '''
    13. 对比 python 对象与生成的 json schame 的结构是否一致
    14. '''
    15. try:
    16. validate(instance=obj, schema=schema)
    17. return True
    18. except Exception as e:
    19. return False

     代码示例:

    test_utils_use.py

    1. import requests
    2. from interface_automation_testing.接口自动化测试_L3.接口鉴权的多种情况与解决方案.jsonschema_utils import JSONSchemaUtils
    3. def test_httpbin_generate_schema():
    4. r = requests.get("https://httpbin.ceshiren.com/get", verify=False)
    5. JSONSchemaUtils.generate_jsonschema_by_file(r.json(), "./datas/httpbin.json")
    6. def test_httpbin_req():
    7. r = requests.get("https://httpbin.ceshiren.com/get", verify=False)
    8. validate_res = JSONSchemaUtils.validate_schema_by_file(r.json(), "./datas/httpbin.json")
    9. assert validate_res == True

    jsonschema_utils.py

    1. import json
    2. from genson import SchemaBuilder
    3. from jsonschema.validators import validate
    4. class JSONSchemaUtils:
    5. @classmethod
    6. def validate_schema(cls, data_obj, schema):
    7. try:
    8. validate(data_obj, schema=schema)
    9. return True
    10. except Exception as e:
    11. print(f"结构体验证失败,失败原因是{e}")
    12. return False
    13. @classmethod
    14. def generate_jsonschema(cls, obj):
    15. builder = SchemaBuilder()
    16. builder.add_object(obj)
    17. return builder.to_schema()
    18. @classmethod
    19. def validate_schema_by_file(cls, data_obj, schema_file):
    20. with open(schema_file) as f:
    21. schema_data = json.load(f)
    22. return cls.validate_schema(data_obj, schema_data)
    23. @classmethod
    24. def generate_jsonschema_by_file(cls, obj, file_path):
    25. json_schema_data = cls.generate_jsonschema(obj)
    26. with open(file_path, "w") as f:
    27. json.dump(json_schema_data, f)

     项目结构:

    2.数据库操作与断言

    接口测试响应验证

    如何在测试过程中验证接口没有 Bug?

    1. 通过接口响应值
    2. 通过查询数据库信息辅助验证
    接口测试数据清理 

    自动化测试过程中,会产生大量的脏数据,如何处理?

    1. 通过 Delete 接口删除
    2. 自动化测试使用干净的测试环境,每次自动化测试执行完成之前或之后做数据还原。
    数据库操作注意事项 

    直接对数据库做查询之外的操作是非常危险的行为

    1. 权限管理严格的公司数据库权限给的非常低
    2. 表结构复杂,随便删除数据会影响测试,甚至会导致系统出现异常
    接口自动化测试常用的数据库操作 
    • 连接与配置
    • 查询数据与断言
    数据库信息 
    • 主机: litemall.hogwarts.ceshiren.com
    • 端口: 13306
    • 用户名: test
    • 密码: test123456

    注意:只有查询权限 

    数据库封装(Python) 
    • 封装数据库配置
    • 封装 sql 查询操作
    • 调用方法执行 sql 语句
    1. import pymysql
    2. # 封装建立连接的对象
    3. def get_connnect():
    4. conn = pymysql.connect(
    5. host="litemall.hogwarts.ceshiren.com",
    6. port=13306,
    7. user="test",
    8. password="test123456",
    9. database="litemall",
    10. charset="utf8mb4"
    11. )
    12. return conn
    13. # 执行sql语句
    14. def execute_sql(sql):
    15. connect = get_connnect()
    16. cursor = connect.cursor()
    17. cursor.execute(sql) # 执行SQL
    18. record = cursor.fetchone() # 查询记录
    19. return record
    20. if __name__ == '__main__':
    21. ret = execute_sql("select * from litemall_cart where goods_name='竹语丝麻印花四件套'")
    22. print(ret)
     查询数据与数据库断言(Python)
    • 查询数据,添加查询条件
    • 断言结果不为 None
    1. import json
    2. import pytest
    3. import requests
    4. from interface_automation_testing.接口自动化测试_L3.数据库操作与断言.db_config import execute_sql
    5. from interface_automation_testing.接口自动化测试_L3.数据库操作与断言.utils.log_util import logger
    6. class TestLitemall:
    7. def setup_class(self):
    8. # 1. 管理端登录接口
    9. url = "http://litemall.hogwarts.ceshiren.com/admin/auth/login"
    10. user_data = {"username": "admin123", "password": "admin123", "code": ""}
    11. r = requests.post(url, json=user_data, verify=False)
    12. self.token = r.json()["data"]["token"]
    13. # 问题: 没有执行test_get_admin_token这个方法,所以self.token 就不会被声明就会报错'TestLitemall' object has no attribute 'token'
    14. # 解决, self.token 的声明一定要在test_add_goods方法执行之前完成,可以使用setup_class 提前完成变量的声明
    15. # 2. 用户端登录接口
    16. url = "http://litemall.hogwarts.ceshiren.com/wx/auth/login"
    17. client_data = {"username": "user123", "password": "user123"}
    18. r = requests.post(url, json=client_data, verify=False)
    19. self.client_token = r.json()["data"]["token"]
    20. # ======= 数据清理,建议使用delete接口不要直接删表中的数据
    21. def teardown(self):
    22. url = "http://litemall.hogwarts.ceshiren.com/admin/goods/delete"
    23. r = requests.post(url, json={"id": self.goods_id}, headers={"X-Litemall-Admin-Token": self.token}, verify=False)
    24. logger.debug(f"删除商品的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    25. # 上架商品接口调试
    26. # ====问题2: goods_name 不能重复,所以需要添加参数化
    27. @pytest.mark.parametrize("goods_name", ["ADcarry12", "ADcarry13"])
    28. def test_add_goods(self, goods_name):
    29. # 3. 上架商品接口
    30. url = "http://litemall.hogwarts.ceshiren.com/admin/goods/create"
    31. goods_data = {
    32. "goods": {"picUrl": "", "gallery": [], "isHot": False, "isNew": True, "isOnSale": True, "goodsSn": "9001",
    33. "name": goods_name}, "specifications": [{"specification": "规格", "value": "标准", "picUrl": ""}],
    34. "products": [{"id": 0, "specifications": ["标准"], "price": "66", "number": "66", "url": ""}],
    35. "attributes": []}
    36. # 问题: token 是 手动复制进去的,一旦发生变化,还需要再次修改
    37. # 解决方案: token 需要自动完成获取,并且赋值
    38. r = requests.post(url, json=goods_data, headers={"X-Litemall-Admin-Token": self.token}, verify=False)
    39. # 打印响应体内容
    40. # print(r.json())
    41. # logger.debug(f"上架商品接口接口的相应信息为{r.json()}")
    42. logger.debug(f"上架商品接口接口的相应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    43. # 4. 获取商品列表
    44. goods_list_url = "http://litemall.hogwarts.ceshiren.com/admin/goods/list"
    45. # 是一个get请求,参数需要通过params也就是url参数传递
    46. goods_data = {
    47. "name": goods_name,
    48. "order": "desc",
    49. "sort": "add_time"
    50. }
    51. r = requests.get(goods_list_url, params=goods_data,
    52. headers={"X-Litemall-Admin-Token": self.token}, verify=False)
    53. self.goods_id = r.json()["data"]["list"][0]["id"]
    54. logger.debug(f"获取商品列表接口的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    55. # 5.获取商品详情接口=========
    56. goods_detail_url = "http://litemall.hogwarts.ceshiren.com/admin/goods/detail"
    57. r = requests.get(goods_detail_url, params={"id": self.goods_id},
    58. headers={"X-Litemall-Admin-Token": self.token}, verify=False)
    59. product_id = r.json()["data"]["products"][0]["id"]
    60. logger.debug(f"获取商品详情接口的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    61. # 6. 添加购物车接口
    62. url = "http://litemall.hogwarts.ceshiren.com/wx/cart/add"
    63. # 问题: goodsId 和 productId 是写死的,变量的传递没有完成
    64. # 解决方案: goodsId 和 productId 从其他的接口获取,并传递给添加购物车接口
    65. cart_data = {"goodsId": self.goods_id, "number": 1, "productId": product_id}
    66. r = requests.post(url, json=cart_data, headers={"X-Litemall-Token": self.client_token}, verify=False)
    67. res = r.json()
    68. logger.info(f"添加购物车接口响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    69. # ===============问题1: 缺少断言
    70. ret = execute_sql(f"select * from litemall_cart where user_id=1 and deleted=0 and goods_name='{goods_name}'")
    71. assert ret is not None
    72. # ===============解决: 添加断言
    73. assert res["errmsg"] == "成功"

    项目结构:

    3.接口鉴权的多种情况与解决方案

    接口鉴权是什么?

    接口鉴权是指对通过接口进行的数据访问进行权限验证,以防止未授权的访问和恶意攻击。具体来说,接口鉴权可以在数据访问请求到达服务器之前,通过验证请求中的用户身份、角色、令牌等信息来确认请求者是否有权访问该接口。如果请求没有通过鉴权验证,服务器将拒绝该请求并返回相应的错误信息。

    在实现接口鉴权时,需要考虑以下几个因素:

    1. 安全性:要保证接口鉴权的安全性,需要对用户的敏感信息进行加密处理,同时对服务器和数据库等核心资产进行安全防护,以防止恶意攻击和数据泄露。
    2. 可扩展性:随着业务的发展和用户数量的增加,接口鉴权的复杂度和工作量也会逐渐增加。因此,在实现接口鉴权时需要考虑可扩展性,以便于后续的升级和维护。
    3. 可维护性:接口鉴权需要有良好的可维护性,以便于在出现异常情况时快速定位和解决问题。同时,也需要对用户反馈和系统日志进行实时监控,以便于及时发现和处理潜在问题。

    总之,接口鉴权是保障数据访问安全的重要组成部分,可以有效防止未授权的访问和恶意攻击,保护系统的稳定性和可靠性。

    接口鉴权通用的解决方案
    • 认证信息的获取
    • 认证信息的携带

     

    后端接口鉴权常用方法 

    cookie 鉴权 
    1. cookie 的获取(根据接口文档获取)
    2. 发送携带 cookie 的请求
      • 直接通过 cookies 参数
      • 通过 Session() 对象
    1. import requests
    2. class TestVerify:
    3. def test_cookies_by_write(self):
    4. # 简单场景,直接写入cookie
    5. url = "https://httpbin.ceshiren.com/cookies"
    6. r = requests.get(url, verify=False, cookies={"teacher": "LiMing"})
    7. print(r.json())
    8. def test_cookies_without_session(self):
    9. # 第一次登陆,植入cookie
    10. set_url = "https://httpbin.ceshiren.com/cookies/set/teacher/LiMing"
    11. r1 = requests.get(set_url, verify=False)
    12. print(r1.json())
    13. # 第二次请求的时候没有携带cookie信息
    14. url = "https://httpbin.ceshiren.com/cookies"
    15. r2 = requests.get(url, verify=False)
    16. print(r2.json())
    17. def test_cookies_session(self):
    18. req = requests.Session()
    19. # 第一次登陆,植入cookie
    20. set_url = "https://httpbin.ceshiren.com/cookies/set/teacher/LiMing"
    21. r1 = req.get(set_url, verify=False)
    22. print(r1.json())
    23. # 第二次请求的时候即可携带cookie信息
    24. url = "https://httpbin.ceshiren.com/cookies"
    25. r2 = req.get(url, verify=False)
    26. print(r2.json())
    token 鉴权
    1. token 的获取(根据接口文档获取)
    2. 发送携带 token 的请求(根据接口文档获取)
    1. import requests
    2. class TestVerify:
    3. def test_token(self):
    4. # 1. 前端登录进去以后,会拿到服务器给的tocken
    5. url = "http://litemall.hogwarts.ceshiren.com/admin/auth/login"
    6. user_data = {"username": "admin123", "password": "admin123", "code": ""}
    7. r = requests.post(url,
    8. json=user_data,
    9. verify=False)
    10. self.token = r.json()["data"]["token"]
    11. print(r.json())
    12. # 2. 之后的请求均携带token
    13. goods_list_url = "http://litemall.hogwarts.ceshiren.com/admin/goods/list"
    14. goods_data = {"name": "LiMing", "order": "desc", "sort": "add_time"}
    15. r = requests.get(goods_list_url,
    16. params=goods_data,
    17. headers={"X-Litemall-Admin-Token": self.token},
    18. verify=False)
    19. print(r.json())
     auth 鉴权(了解即可)
    • 在基本 HTTP 身份验证中,请求包含格式为 的标头字段Authorization: Basic
    • 其中credentials是 ID 和密码的Base64编码,由单个冒号连接:。

     

    auth 鉴权-代码示例 
    1. import requests
    2. from requests.auth import HTTPBasicAuth
    3. class TestVerify:
    4. def test_basic_auth(self):
    5. # 正确示例
    6. r = requests.get("https://httpbin.ceshiren.com/basic-auth/admin/666666",
    7. verify=False,
    8. auth=HTTPBasicAuth("admin", "666666"))
    9. print(r.json())
    10. # 错误示例
    11. # r = requests.get("https://httpbin.ceshiren.com/basic-auth/admin/666666",
    12. # verify=False,
    13. # auth=HTTPBasicAuth("admin2", "666666"))
    14. # print(r.json())

     

    4.电子商城接口自动化测试实战

    接口测试流程
    电子商城需求分析
    • 商城管理后台

    • 商城客户端

    商城业务场景
    • 商品上架
    • 商品查询
    • 加入购物车

    研发技术评审
    • 管理后台接口文档
    • https://litemall.hogwarts.ceshiren.com/swagger-ui.html#
     接口测试用例设计思路

    添加购物车流程脚本编写 
    1. 上架商品
    2. 查询商品列表,获取商品ID
    3. 查询商品详情,获取商品库存ID
    4. 加入购物车

     

    脚本优化-参数化(Python) 
    • 使用pytest parametrize装饰器实现商品名称的参数化
    • @pytest.mark.parametrize("goods_name", ["name1", "name2"])  
    脚本优化-添加日志(Python) 
    • 新建日志配置
    • 在用例中使用配置好的日志实例
    1. import logging
    2. import os
    3. from logging.handlers import RotatingFileHandler
    4. # 绑定绑定句柄到logger对象
    5. logger = logging.getLogger(__name__)
    6. # 获取当前工具文件所在的路径
    7. root_path = os.path.dirname(os.path.abspath(__file__))
    8. # 拼接当前要输出日志的路径
    9. root_len = len(root_path)
    10. strs = root_path[0:root_len-6]
    11. log_dir_path = os.sep.join([strs,f'datas\logs'])
    12. if not os.path.isdir(log_dir_path):
    13. os.mkdir(log_dir_path)
    14. # 创建日志记录器,指明日志保存路径,每个日志的大小,保存日志的上限
    15. file_log_handler = RotatingFileHandler(os.sep.join([log_dir_path, 'log.log']),
    16. maxBytes=1024 * 1024, backupCount=10,
    17. encoding="utf-8")
    18. # 设置日志的格式
    19. date_string = '%Y-%m-%d %H:%M:%S'
    20. formatter = logging.Formatter(
    21. '[%(asctime)s] [%(levelname)s] [%(filename)s]/[line: %(lineno)d]/[%(funcName)s] %(message)s ',
    22. date_string)
    23. # 日志输出到控制台的句柄
    24. stream_handler = logging.StreamHandler()
    25. # 将日志记录器指定日志的格式
    26. file_log_handler.setFormatter(formatter)
    27. stream_handler.setFormatter(formatter)
    28. # 为全局的日志工具对象添加日志记录器
    29. # 绑定绑定句柄到logger对象
    30. logger.addHandler(stream_handler)
    31. logger.addHandler(file_log_handler)
    32. # 设置日志输出级别
    33. logger.setLevel(level=logging.INFO)
    34. def prit_path():
    35. print(root_path)
    36. print(log_dir_path)
    37. prit_path()
    脚本优化-数据清理(Python)
    • 在用例执行完成之后调用删除接口完成数据清理
    1. import json
    2. import pytest
    3. import requests
    4. from interface_automation_testing.接口自动化测试_L3.电子商城接口自动化测试实战.utils.log_util import logger
    5. class TestLitemall:
    6. def setup_class(self):
    7. # 1. 管理端登录接口
    8. url = "http://litemall.hogwarts.ceshiren.com/admin/auth/login"
    9. user_data = {"username": "hogwarts", "password": "test12345", "code": ""}
    10. r = requests.post(url, json=user_data, verify=False)
    11. self.token = r.json()["data"]["token"]
    12. # 2. 用户端登录接口
    13. url = "http://litemall.hogwarts.ceshiren.com/wx/auth/login"
    14. client_data = {"username": "user123", "password": "user123"}
    15. r = requests.post(url, json=client_data, verify=False)
    16. self.client_token = r.json()["data"]["token"]
    17. def teardown(self):
    18. url = "http://litemall.hogwarts.ceshiren.com/admin/goods/delete"
    19. r = requests.post(url,
    20. json={"id": self.goods_id},
    21. headers={"X-Litemall-Admin-Token": self.token},
    22. verify=False)
    23. logger.info(f"删除商品的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    24. @pytest.mark.parametrize("goods_name", ["ADcarry12", "ADcarry13"])
    25. def test_add_goods(self, goods_name):
    26. # 上架商品
    27. url = "http://litemall.hogwarts.ceshiren.com/admin/goods/create"
    28. goods_data = {
    29. "goods": {"picUrl": "", "gallery": [], "isHot": False, "isNew": True, "isOnSale": True, "goodsSn": "9001",
    30. "name": goods_name},
    31. "specifications": [{"specification": "规格", "value": "标准", "picUrl": ""}],
    32. "products": [{"id": 0, "specifications": ["标准"], "price": "66", "number": "66", "url": ""}],
    33. "attributes": []
    34. }
    35. r = requests.post(url, json=goods_data, headers={"X-Litemall-Admin-Token": self.token})
    36. logger.info(f"上架商品接口接口的相应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    37. # 获取商品列表
    38. goods_list_url = "http://litemall.hogwarts.ceshiren.com/admin/goods/list"
    39. goods_data = {
    40. "name": goods_name,
    41. "order": "desc",
    42. "sort": "add_time"
    43. }
    44. r = requests.get(goods_list_url,
    45. params=goods_data,
    46. headers={"X-Litemall-Admin-Token": self.token},
    47. verify=False)
    48. self.goods_id = r.json()["data"]["list"][0]["id"]
    49. logger.info(f"获取商品列表接口的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    50. # 获取商品详情
    51. goods_detail_url = "http://litemall.hogwarts.ceshiren.com/admin/goods/detail"
    52. r = requests.get(goods_detail_url,
    53. params={"id": self.goods_id},
    54. headers={"X-Litemall-Admin-Token": self.token},
    55. verify=False)
    56. product_id = r.json()["data"]["products"][0]["id"]
    57. logger.info(f"获取商品详情接口的响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    58. # 添加购物车接口
    59. url = "http://litemall.hogwarts.ceshiren.com/wx/cart/add"
    60. cart_data = {"goodsId": self.goods_id, "number": 1, "productId": product_id}
    61. r = requests.post(url, json=cart_data, headers={"X-Litemall-Token": self.client_token})
    62. res = r.json()
    63. logger.info(f"添加购物车接口响应信息为{json.dumps(r.json(), indent=2, ensure_ascii=False)}")
    64. # 断言
    65. assert res["errmsg"] == "成功"
     脚本优化-报告展示
    • 安装allure相关依赖
    1. # 生成报告信息
    2. pytest .\test_litemall.py --alluredir=./datas/report
    3. # 生成报告在线服务,查看报告
    4. allure serve ./datas/report

    运行结果:

    项目结构:

     

    项目地址:https://gitee.com/coderPatrickStar/template/tree/master/python_software_testing

  • 相关阅读:
    OpenCV每日函数 计算摄影模块(1) 图像修复算法 inpaint函数
    数据库设计
    JAVA经典百题之圆的面积
    TCP半连接队列和全连接队列
    linux高频面试题目
    VMware Horizon 8 运维系列(二)win10设置共享桌面图标
    socket.error: [Errno 10049]错误
    Linux编程——内核模块
    C++11的内容介绍
    品牌线上渠道管控,如何考察第三方控价公司
  • 原文地址:https://blog.csdn.net/qq_56444564/article/details/133821389