一、接口自动化生成自动化脚本的思路
1、接口文档发给大模型2、让大模型编写接口功能用例
3、再让大模型依据接口功能用例编写自动化用例
4、把自动化用例保存在指定目录下
二、LangChain设计
1、从完整的swagger_json中提取指定接口信息
编写代码的提示词
#背景
需要从swagger文档里面提取出对应的配置信息,根据用户输入的接口名称,提取对应的内容
#需求
用户传入接口的名称列表,从swagger文档的json中找到接口名称的summary,还有接口的请求方式,path,需要把整个接口的节点的信息全部提取出来。在接口信息的response中,200节点下面有schema节点,里面引用了一个DO对象。该DO对象是在definitions节点中定义的,需要找到对应DO对象,把相关信息过滤出来
#入参
1、完整的swgger_json
2、需要提取接口的名称列表summary_list
swagger_json示例格式:
```json
{"swagger":"2.0","info":{"description":"卖家中心API接口","version":"7.0","title":"卖家中心Api文档"},"host":"59.36.173.55:7003","basePath":"/","tags":[{"name":"distribution-goods-seller-controller","description":"分销商品API"}],"paths":{"/seller/distribution/goods":{"put":{"tags":["distribution-goods-seller-controller"],"summary":"分销商品返利设置","operationId":"settingGoodsUsingPUT","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"Authorization","in":"header","description":"令牌","required":false,"type":"string"},{"name":"goods_id","in":"query","description":"商品id","required":true,"type":"integer","format":"int32"},{"name":"grade1_rebate","in":"query","description":"1级提成金额","required":true,"type":"number","format":"double"},{"name":"grade2_rebate","in":"query","description":"2级提成金额","required":true,"type":"number","format":"double"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/DistributionGoods"}},"201":{"description":"Created"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/seller/distribution/goods/{goods_id}":{"get":{"tags":["distribution-goods-seller-controller"],"summary":"分销商品返利获取","operationId":"querySettingUsingGET","produces":["*/*"],"parameters":[{"name":"Authorization","in":"header","description":"令牌","required":false,"type":"string"},{"name":"goods_id","in":"path","description":"商品id","required":true,"type":"integer","format":"int32"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/DistributionGoods"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}},"/seller/distribution/setting":{"get":{"tags":["distribution-goods-seller-controller"],"summary":"获取分销设置:1开启/0关闭","operationId":"settingUsingGET","produces":["*/*"],"parameters":[{"name":"Authorization","in":"header","description":"令牌","required":false,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/SuccessMessage"}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not Found"}}}}},"definitions":{"DistributionGoods":{"type":"object","required":["goods_id","grade1_rebate","grade2_rebate"],"properties":{"goods_id":{"type":"integer","format":"int32","description":"商品id","allowEmptyValue":false},"grade1_rebate":{"type":"number","format":"double","description":"1级提成金额","allowEmptyValue":false},"grade2_rebate":{"type":"number","format":"double","description":"2级提成金额","allowEmptyValue":false}},"title":"DistributionGoods"},"SuccessMessage":{"type":"object","properties":{"message":{"type":"object"}},"title":"SuccessMessage"}}}
```
#返回值
返回一个json,包含paths、definitions两个节点
def fetch_swagger_json(swagger_url):
"""
从Swagger接口获取JSON数据
:param swagger_url: Swagger接口URL
:return: Swagger JSON数据
"""
try:
response = requests.get(swagger_url)
response.raise_for_status() # 检查请求是否成功
return response.json()
except requests.exceptions.RequestException as e:
print(f"获取Swagger数据失败: {e}")
return None
def extract_swagger_info(swagger_json, summary_list):
"""
从Swagger JSON中提取指定接口的信息
:param swagger_json: 完整的Swagger JSON文档
:param summary_list: 需要提取的接口summary列表
:return: 包含paths和definitions的JSON
"""
try:
# 如果传入的是字符串,则解析为字典
if isinstance(swagger_json, str):
swagger_data = json.loads(swagger_json)
else:
swagger_data = swagger_json
result = {
"paths": {},
"definitions": {}
}
# 收集所有需要提取的DO对象引用
do_refs = set()
# 遍历paths中的所有接口
for path, methods in swagger_data.get("paths", {}).items():
for method, details in methods.items():
if isinstance(details, dict) and details.get("summary") in summary_list:
# 添加到结果中的paths
if path not in result["paths"]:
result["paths"][path] = {}
result["paths"][path][method] = details
# 检查200响应中的schema引用
responses = details.get("responses", {})
if "200" in responses:
schema = responses["200"].get("schema", {})
if "$ref" in schema:
do_refs.add(schema["$ref"])
# 提取definitions
for ref in do_refs:
# 解析引用路径,如"#/definitions/DistributionGoods"
parts = ref.split("/")
if len(parts) == 3 and parts[1] == "definitions":
do_name = parts[2]
if do_name in swagger_data.get("definitions", {}):
result["definitions"][do_name] = swagger_data["definitions"][do_name]
return result
except Exception as e:
return {"error": str(e)}
def main(swagger_url,summary_list):
# 1. 获取Swagger JSON数据
swagger_json = fetch_swagger_json(swagger_url)
if not swagger_json:
print("无法获取Swagger数据,请检查网络或URL是否正确")
return
# 2. 提取指定接口信息
result = extract_swagger_info(swagger_json, summary_list)
# 3. 输出结果
return json.dumps(result, indent=2, ensure_ascii=False)
if __name__ == "__main__":
api_json = main(swagger_url = "url",summary_list = [ "接口"])
2、调用LangChain生成测试用例
llm = ChatOpenAI(
openai_api_base="",
api_key="",
temperature=0.8,
max_tokens=10240,
model_name="",
)
def read_prompt(filename):
"""
读取当前脚本同级目录下的prompts文件夹中的指定文件
Args:
filename (str): 要读取的文件名
Returns:
str: 文件内容
"""
# 获取当前脚本所在目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 构建prompts文件夹路径
prompts_dir = os.path.join(current_dir, 'prompts')
# 构建目标文件的完整路径
file_path = os.path.join(prompts_dir, filename)
# 检查文件是否存在
if not os.path.exists(file_path):
raise FileNotFoundError(f"Prompt file '{filename}' not found in '{prompts_dir}'")
# 读取文件内容
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
def call_chain(api_json,requirements):
#第一步:让大模型根据接口的json和补充需求,生成一份标准的接口需求文档
prompt_template_summary = PromptTemplate(
input_variables=["api_json", "requirements"],
template=read_prompt("summary_prompt.md"),
template_format="jinja2"
)
#定义第一个节点
summary_chain = LLMChain(llm=llm, prompt=prompt_template_summary, verbose=True, output_key="summary_result")
prompt_template_summary_case = PromptTemplate(
input_variables=["summary_result"],
template=read_prompt("case_prompt.md"),
template_format="jinja2"
)
summary_chain_case = LLMChain(llm=llm, prompt=prompt_template_summary_case, verbose=True, output_key="api_case")
#第三个节点
prompt_template_script = PromptTemplate(
input_variables=["api_case"],
template=read_prompt("script_prompt.md"),
template_format="jinja2"
)
script_chain = LLMChain(llm=llm, prompt=prompt_template_script, verbose=True, output_key="script_result")
#创建一个顺序链,把两个节点按照顺序组装
all_chain = SequentialChain(
chains=[summary_chain,summary_chain_case,script_chain],
input_variables=["api_json","requirements"],
output_variables=["api_case","script_result"],
verbose=True
)
#运行整个链
result = all_chain.invoke({"api_json":api_json,"requirements":requirements})
print(result)
3、大模型根据接口测试用例生成接口自动化脚本
未完待续