目录:
- 接口加密与解密
- 环境准备
- 原理
- 实战练习
- 多套被测环境
- 多环境介绍
- 多套被测环境切换的意义和价值
- 实现目标
- 实现方案-环境管理
- 环境切换
- 通过环境变量进行切换
- 使用命令行进行切换
- 多响应类型封装设计
- 多协议封装应用场景
- 实战演示
- xml 转换 dict(Python)
- 多协议封装(Python)
- 电子商城接口自动化测试框架实战
1.接口加密与解密
环境准备
- 对响应加密的接口。对它发起一个get请求后,得到一个加密过后的响应信息。(如果有可用的加密过的接口以及了解它的解密方法,可以跳过)
- 准备一个加密文件.
- 使用python命令在有加密文件的所在目录启动一个服务
- 访问该网站
- 创建一个demo.json文件
- 使用
base64 demo.json >demo.txt
命令 - demo.txt我放在最后了,有项目地址
启动服务器:
- python -m http.server 9999
运行结果:
原理
在得到响应后对响应做解密处理:
- 如果知道使用的是哪个通用加密算法的话,可以自行解决。
- 如果不了解对应的加密算法的话,可以让研发提供加解密的lib。
- 如果既不是通用加密算法、研发也无法提供加解密的lib的话,可以让加密方提供远程解析服务,这样算法仍然是保密的。
运行以下代码之前先把上边那个服务器开启!9999
test_encode.py
import json
import requests
import base64
class TestApiRequest:
def test_decode(self):
url = "http://localhost:9999/demo.txt"
r = requests.get(url=url)
res = json.loads(base64.b64decode(r.content))
print()
print(res)
print(r.text)
req_data = {
"method": "get",
"url": "http://localhost:9999/demo.txt",
"headers": None,
"encoding": "base64"
}
def send(self, data: dict):
res = requests.request(method=data["method"], url=data["url"], headers=data["headers"])
if data["encoding"] == "base64":
return json.loads(base64.b64decode(res.content))
# 把加密过后的响应值发给第三方服务,.让第三方太做解密然后返回解密过后的信息
elif data["encoding"] == "private":
return requests.post("url", data=res.content)
def test_send(self):
print()
print(self.send(self.req_data))
运行结果:
实战练习
- 调用python自带的base64,直接对返回的响应做解密,即可得到解密后的响应。
- 封装对于不同算法的处理方法。
2.多套被测环境
多环境介绍
环境 | 使用场景 | 备注 |
---|---|---|
dev | 开发环境 | 开发自测 |
QA | 测试环境 | QA日常测试 |
preprod | 预发布环境 | 回归测试、产品验测试 |
prod | 线上环境 | 用户使用的环境 |
多套被测环境切换的意义和价值
- 访问信息: 不同环境的域名或ip都不一样,部分产品Host也会有区别
- 配置信息: DB、Redis、ES等中间件的配置信息不同环境也不一样
# 每条用例的url都是写死的,一旦切换环境,所有的用例都要修改。
r = requests.post("https://httpbin.ceshiren.com/post",data=data)
实现目标
- 全局控制,一键切换
- 可维护性和扩展性强,可以应对不断演进的环境变化。
实现方案-环境管理
- 使用环境管理文件
- yaml
- ini
- 常量类
- 使用不同的文件管理不同的环境
- 在接口用例中只指定path,不指定url
# test.yaml 测试环境的配置
env_config:
base_url: https://httpbin.org/
db_config:
host: httpbin.org
username: xxxx
password: xxxx
redis_config:
host: httpbin.org
port: 8100
# dev.yaml 开发环境的配置
env_config:
base_url: https://httpbin.bai.com/
db_config:
host: httpbin.bai.com
username: xxxx
password: xxxx
redis_config:
host: httpbin.bai.com
port: 8100
环境切换
- 通过环境变量进行切换
- 通过命令行参数进行切换
通过环境变量进行切换
- 设置环境变量
- 读取环境变量
# mac设置环境变量
export env=dev
# windows 设置环境变量
set env=dev
# 在python中读取环境变量
import os
import requests
import yaml
class TestMulitiEnv:
def setup_class(self):
default = os.getenv("env", default="test")
data = yaml.safe_load(open(f"./datas/environment/{default}.yaml", encoding="utf-8"))
self.env = data
self.base_url = self.env["base_url"]
# 开发环境
def test_devenv(self):
path = "/get"
r = requests.get(self.base_url + path, verify=False)
assert r.json()["headers"]["Host"] == "httpbin.org"
# 测试环境
def test_testenv(self):
path = "/post"
r = requests.post(self.base_url + path, verify=False)
assert r.json()["headers"]["Host"] == "httpbin.ceshiren.com"
dev.yaml
#开发环境的配置文件
base_url: https://httpbin.ceshiren.com/
test.yaml
#测试环境的配置文件
base_url: https://httpbin.org/
项目结构:
运行结果:(一个通过,一个失败,原因:只能开启一个环境变量)
set env=test
pytest .\test_env.py
使用命令行进行切换
与《selenium 多浏览器处理》章节逻辑相同
# conftest.py
global_env = {}
def pytest_addoption(parser):
# group 将下面所有的 option都展示在这个group下。
mygroup = parser.getgroup("hdc")
# 注册一个命令行选项
mygroup.addoption("--env",
# 参数的默认值
default='test',
# 存储的变量
dest='env',
# 参数的描述信息
help='设置接口自动化测试默认的环境'
)
def pytest_configure(config):
default_ev = config.getoption("--env")
tmp = {"env": default_ev}
global_env.update(tmp)
# test_muliti_env.py
import requests
import yaml
from interface_automation_testing.接口自动化测试_L4.多套被测环境.conftest import global_env
class TestMulitiEnv:
def setup_class(self):
# 获取命令行配置的环境变量
default = global_env.get("env")
data = yaml.safe_load(open(f"./datas/environment/{default}.yaml", encoding="utf-8"))
self.env = data
self.base_url = self.env["base_url"]
def test_devenv(self):
path = "/get"
r = requests.get(self.base_url + path, verify=False)
assert r.json()["headers"]["Host"] == "httpbin.ceshiren.com"
def test_testenv(self):
path = "/post"
r = requests.post(self.base_url + path, verify=False)
assert r.json()["headers"]["Host"] == "httpbin.org"
在终端中运行以下代码:
pytest .\test_muliti_env.py --env=dev
pytest .\test_muliti_env.py --env=test
运行结果:
项目结构:
3.多响应类型封装设计
多协议封装应用场景
- 问题:
- 响应值不统一
- json
- xml
- 断言比较困难
- 响应值不统一
- 解决方案:获得的响应信息全部转换为结构化的数据进行处理
解决方案:
没有改进的:
改进之后的:
实战演示
实战目标: 对响应值做二次封装,可以使用统一提取方式完成断言
xml 转换 dict(Python)
- 环境准备: pip install xmltodict
- 依赖包版本: 0.13
import xmltodict
import requests
def test_xml_dict():
"""
xml转换为json
:return:
"""
res = requests.get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
dict_res = xmltodict.parse(res.text)
print(dict_res)
print(type(dict_res))
多协议封装(Python)
import requests
import xmltodict
from requests import Response
def response_dict(response: Response):
res_text = response.text
if res_text.startswith("<?xml"):
final_dict = xmltodict.parse(res_text)
elif res_text.startswith("<!DOCTYPE html>"):
final_dict = "html"
else:
final_dict = response.json()
return final_dict
def test_response_dict():
# xml
# res = requests.get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
# json
res = requests.get("https://httpbin.ceshiren.com/get", verify=False)
final_res = response_dict(res)
print(type(final_res))
print(final_res)
assert isinstance(final_res, dict)
4.电子商城接口自动化测试框架实战
现有问题
- 可维护性差:一个 api 发生变化,需要修改用例文件
- 可读性差:无法从代码中看出来明确的业务逻辑
- 断言能力差:响应内容只能一层一层提取
架构优化设计
添加领域模型
- domain 更多代表业务模式的抽象,没有具体的实现
待更新............................................................................