AI自动生成接口测试脚本全流程

发布于:2025-08-12 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、接口自动化生成自动化脚本的思路

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、大模型根据接口测试用例生成接口自动化脚本

未完待续