Commit cd4d74b8 authored by 王英豪's avatar 王英豪

1123

parent 53f0e3f6
...@@ -57,7 +57,7 @@ urlpatterns = [ ...@@ -57,7 +57,7 @@ urlpatterns = [
# path('', include("automated_main.url.api_automation_url.api_module_url")), # path('', include("automated_main.url.api_automation_url.api_module_url")),
# 获取api环境列表 # 获取api环境列表
path('', include("automated_main.url.api_automation_url.api_environment_url")), # path('', include("automated_main.url.api_automation_url.api_environment_url")),
# # API测试用例 # # API测试用例
...@@ -67,20 +67,12 @@ urlpatterns = [ ...@@ -67,20 +67,12 @@ urlpatterns = [
# path('', include("automated_main.url.api_automation_url.api_business_test_url")), # path('', include("automated_main.url.api_automation_url.api_business_test_url")),
# API数据库 # API数据库
path('', include("automated_main.url.api_automation_url.api_database_url")), # path('', include("automated_main.url.api_automation_url.api_database_url")),
# # API任务管理 # # API任务管理
# path('', include("automated_main.url.api_automation_url.api_test_task_url")), # path('', include("automated_main.url.api_automation_url.api_test_task_url")),
# API接口管理
path('', include("automated_main.url.api_automation_url.api_management_url")),
# API场景用例
path('', include("automated_main.url.api_automation_url.api_scenarios_case_url")),
# API测试计划
path('', include("automated_main.url.api_automation_url.api_plan_url")),
# 性能测试-性能项目 # 性能测试-性能项目
path('', include("automated_main.url.performance_test_url.performance_project_url")), path('', include("automated_main.url.performance_test_url.performance_project_url")),
......
...@@ -15,7 +15,7 @@ from automated_main.models.ui_automation.ui_test_task import UITestTask, UITestR ...@@ -15,7 +15,7 @@ from automated_main.models.ui_automation.ui_test_task import UITestTask, UITestR
""" """
# from automated_main.models.api_automation.api_project import APIProject # from automated_main.models.api_automation.api_project import APIProject
# from automated_main.models.api_automation.api_module import APIModule # from automated_main.models.api_automation.api_module import APIModule
from automated_main.models.api_automation.api_environment import APIEnvironment # from automated_main.models.api_automation.api_environment import APIEnvironment
""" """
8.19 弃用 8.19 弃用
""" """
...@@ -25,11 +25,7 @@ from automated_main.models.api_automation.api_environment import APIEnvironment ...@@ -25,11 +25,7 @@ from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.performance_test.performance_project import PerformanceProject from automated_main.models.performance_test.performance_project import PerformanceProject
from automated_main.models.performance_test.performance_script import PerformanceScript from automated_main.models.performance_test.performance_script import PerformanceScript
from automated_main.models.performance_test.performance_report import PerformanceReport from automated_main.models.performance_test.performance_report import PerformanceReport
from automated_main.models.api_automation.api_database import APIDatabase #
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCaseAssociated, ApiScenariosCaseAssociated
from automated_main.models.api_automation.api_test_plan import ApiTestPlan
......
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:44
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/4/14 17:20
# @Author : wangyinghao
# @FileName: api_business_test.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.db import models
# from automated_main.models.api_automation.api_project import APIProject
# from automated_main.models.api_automation.api_module import APIModule
# from automated_main.models.api_automation.api_test_case import ApiTestCase
#
#
# class ApiBusinessTest(models.Model):
# """
# api业务测试表
# """
#
# api_business_test_name = models.CharField("API业务测试名称", max_length=100, null=False)
# api_business_test_describe = models.TextField("API业务测试描述", max_length=5000, null=True)
# api_project = models.ForeignKey(APIProject, on_delete=models.CASCADE)
# updata_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_business_test_name
#
#
# class ApiBusinessTestAssociated(models.Model):
# """
# API业务测试关联表
# """
# bid = models.ForeignKey(ApiBusinessTest, on_delete=models.CASCADE)
# api_module = models.ForeignKey(APIModule, on_delete=models.CASCADE)
# api_test_case = models.ForeignKey(ApiTestCase, on_delete=models.CASCADE)
# case_steps = models.CharField("操作步骤", max_length=100, null=False)
# updata_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return str(self.bid)
from django.db import models
class APIDatabase(models.Model):
"""
API数据库
"""
api_database_title = models.CharField("API数据库名称", max_length=200, null=False)
api_host = models.CharField("API_Host", max_length=200, null=False)
api_port = models.CharField("端口号", max_length=200, null=False)
user = models.CharField("用户名", max_length=200, null=False)
password = models.CharField("密码", max_length=200, null=False)
database = models.CharField("数据库表名", max_length=200, null=False)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
updata_time = models.DateTimeField("更新时间", auto_now_add=True)
def __str__(self):
return self.api_database_title
# -*- coding: utf-8 -*-
# @Time : 2021/3/25 15:00
# @Author : wangyinghao
# @FileName: api_environment.py
# @Software: PyCharm
from django.db import models
class APIEnvironment(models.Model):
"""
API环境设置
"""
api_environment_name = models.CharField("API环境名称", max_length=200, null=False)
api_title = models.CharField("API环境标题名称", max_length=200, null=False)
api_environment_describe = models.TextField("API环境描述", default="", null=True)
status = models.BooleanField("状态", default=1)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
update_time = models.DateTimeField("更新时间", auto_now_add=True)
def __str__(self):
return self.api_environment_name
class APIGlobalVariable(models.Model):
"""
Api环境全局变量
"""
api_environment = models.ForeignKey(APIEnvironment, on_delete=models.CASCADE)
api_global_variable_name = models.TextField("全局变量名称", max_length=5000, null=True)
api_global_variable_value = models.TextField("全局变量值", max_length=5000, null=True)
api_global_variable_describe = models.TextField("全局变量描述", max_length=5000, null=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
update_time = models.DateTimeField("更新时间", auto_now_add=True)
def __str__(self):
return self.api_global_variable_name
# -*- coding: utf-8 -*-
# @Time : 2022/7/5 11:22
# @Author : wangyinghao
# @Site :
# @File : api_interfaces_case.py
# @Software: PyCharm
from django.db import models
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.models.api_automation.api_management import ApiManagement
class ApiInterfacesCase(models.Model):
"""
接口测试用例
"""
api_interfaces_case_name = models.CharField("接口测试用例名称", max_length=200, null=False)
api_documentation = models.TextField("API接口文档地址", max_length=5000, null=True)
api_management = models.ForeignKey(ApiManagement, on_delete=models.CASCADE)
api_environment = models.ForeignKey(APIEnvironment, on_delete=models.CASCADE)
api_method = models.IntegerField("请求方法", null=False) # 1:get 2.post 3:put 4:delete
api_url = models.TextField("API请求地址", null=False)
# 1:form-data 2: json 3:x-www-form-urlencoded
api_parameter_types = models.IntegerField("参数类型", null=False)
api_headers = models.TextField("请求头", null=False)
api_parameter_body = models.TextField("参数内容", null=False)
api_assert_type = models.IntegerField("断言类型", null=False) # 1:包含contains 2: 匹配mathches 3:数据库校验 4:code状态码
dataBase = models.ForeignKey(APIDatabase, on_delete=models.CASCADE, blank=True, null=True)
database_sql = models.TextField("数据库SQL", max_length=8000, null=True, blank=True)
api_assert_text = models.TextField("断言结果", null=False)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return self.api_interfaces_case_name
class ApiInterfacesParameterExtraction(models.Model):
"""
Api提取变量表
"""
api_test_case = models.ForeignKey(ApiInterfacesCase, on_delete=models.CASCADE)
api_variable_results = models.TextField("变量提取结果", max_length=5000, null=True)
api_value_variable = models.TextField("提取变量", max_length=5000, null=True)
api_key_variable = models.TextField("关键字变量名称", max_length=5000, null=True)
def __str__(self):
return self.api_key_variable
class ApiInterfacesParameterData(models.Model):
"""
Parameter参数
"""
api_test_case = models.ForeignKey(ApiInterfacesCase, on_delete=models.CASCADE)
api_parameter_name = models.CharField("参数名称", max_length=500, null=True)
api_must_parameter = models.TextField("必填", max_length=50, null=True)
api_parameter_value = models.TextField("参数值", max_length=5000, null=True)
api_field_describe = models.TextField("字段描述", max_length=5000, null=True)
def __str__(self):
return self.api_parameter_name
# -*- coding: utf-8 -*-
# @Time : 2022/5/24 21:12
# @Author : wangyinghao
# @Site :
# @File : api_management.py
# @Software: PyCharm
from django.db import models
from django.utils import timezone
IS_ROOT = 0
class ApiManagement(models.Model):
name = models.CharField('name', blank=False, default="", max_length=200)
description = models.TextField('description', blank=True, default='')
parent = models.IntegerField('父节点', blank=False, default=IS_ROOT)
yapi_id = models.CharField("YAPIID", blank=True, max_length=2000, null=True)
create_time = models.DateTimeField(auto_now_add=True, blank=True, null=True)
update_time = models.DateTimeField(auto_now_add=True, blank=True, null=True)
def __str__(self):
return self.name
# -*- coding: utf-8 -*-
# @Time : 2021/3/3 10:57
# @Author : wangyinghao
# @FileName: api_module.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.db import models
# from automated_main.models.api_automation.api_project import APIProject
#
#
# class APIModule(models.Model):
# """
# API模块表
# """
# api_project = models.ForeignKey(APIProject, on_delete=models.CASCADE, null=True)
# api_module_name = models.CharField("API模块名称", max_length=50, null=False)
# api_module_describe = models.TextField("API模块描述", default="", null=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
# updata_time = models.DateTimeField("更新时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_module_name
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:44
# @Author : wangyinghao
# @FileName: api_project.py
# @Software: PyCharm
# from django.db import models
#
#
"""
8.19 弃用
"""
# # Create your models here.
# class APIProject(models.Model):
# """
# API项目表
# """
# api_project_name = models.CharField("API项目名称", max_length=50, null=False)
# describe = models.TextField("描述", default="", max_length=2000, null=True)
# status = models.BooleanField("状态", default=1)
# updata_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_project_name
# -*- coding: utf-8 -*-
# @Time : 2022/7/20 10:07
# @Author : wangyinghao
# @Site :
# @File : api_scenarios_case.py
# @Software: PyCharm
from django.db import models
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase
class ApiScenariosCase(models.Model):
"""
API场景测试表
"""
api_scenarios_case_name = models.CharField("API场景测试名称", max_length=200, null=False)
api_scenarios_case_describe = models.TextField("API业务测试描述", max_length=5000, null=True)
api_management = models.ForeignKey(ApiManagement, on_delete=models.CASCADE)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return self.api_scenarios_case_name
class ApiScenariosCaseAssociated(models.Model):
"""
API场景测试关联表
"""
sid = models.ForeignKey(ApiScenariosCase, on_delete=models.CASCADE)
interfaces_case = models.ForeignKey(ApiInterfacesCase, on_delete=models.CASCADE)
case_steps = models.CharField("操作步骤", max_length=100, null=False)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return str(self.sid)
# -*- coding: utf-8 -*-
# @Time : 2021/3/29 17:30
# @Author : wangyinghao
# @FileName: api_test_case.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.db import models
# from automated_main.models.api_automation.api_module import APIModule
# from automated_main.models.api_automation.api_environment import APIEnvironment
# from automated_main.models.api_automation.api_database import APIDatabase
#
#
# class ApiTestCase(models.Model):
# """
# Api测试用例表
# """
# api_test_case_name = models.TextField("API测试用例名称", max_length=5000, null=False)
# api_documentation = models.TextField("API接口文档地址", max_length=5000, null=True)
# api_module = models.ForeignKey(APIModule, on_delete=models.CASCADE)
# api_environment = models.ForeignKey(APIEnvironment, on_delete=models.CASCADE)
# api_method = models.IntegerField("请求方法", null=False) # 1:get 2.post 3:put 4:delete
# api_url = models.TextField("API请求地址", null=False)
# # 1:form-data 2: json 3:x-www-form-urlencoded
# api_parameter_types = models.IntegerField("参数类型", null=False)
# api_headers = models.TextField("请求头", null=False)
# api_parameter_body = models.TextField("参数内容", null=False)
# api_assert_type = models.IntegerField("断言类型", null=False) # 1:包含contains 2: 匹配mathches 3:数据库校验 4:code状态码
# dataBase = models.ForeignKey(APIDatabase, on_delete=models.CASCADE, blank=True, null=True)
# database_sql = models.TextField("数据库SQL", max_length=8000, null=True, blank=True)
# api_assert_text = models.TextField("断言结果", null=False)
# update_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_test_case_name
#
#
# class ApiParameterExtraction(models.Model):
# """
# Api提取变量表
# """
# api_test_case = models.ForeignKey(ApiTestCase, on_delete=models.CASCADE)
# api_variable_results = models.TextField("变量提取结果", max_length=5000, null=True)
# api_value_variable = models.TextField("提取变量", max_length=5000, null=True)
# api_key_variable = models.TextField("关键字变量名称", max_length=5000, null=True)
#
# def __str__(self):
# return self.api_key_variable
#
#
# class ApiParameterData(models.Model):
# """
# Parameter参数
# """
# api_test_case = models.ForeignKey(ApiTestCase, on_delete=models.CASCADE)
# api_parameter_name = models.CharField("参数名称", max_length=500, null=True)
# api_must_parameter = models.TextField("必填", max_length=50, null=True)
# api_parameter_value = models.TextField("参数值", max_length=5000, null=True)
# api_field_describe = models.TextField("字段描述", max_length=5000, null=True)
#
# def __str__(self):
# return self.api_parameter_name
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 14:36
# @Author : wangyinghao
# @Site :
# @File : api_test_plan.py
# @Software: PyCharm
from django.db import models
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_database import APIDatabase
class ApiTestPlan(models.Model):
"""
API计划表
"""
api_test_plan_name = models.CharField("API测试计划名称", max_length=100, blank=False, default="")
api_test_plan_describe = models.TextField("描述", default="", null=True)
status = models.IntegerField("状态:", default=0) # 未执行、执行中、执行完成、排队中
cases = models.TextField("关联API用例", default="")
api_send_email = models.CharField("API邮件发送", max_length=9999, blank=True, default="", null=True)
api_send_enterprise_wechat = models.IntegerField("API企业微信发送消息", blank=True, default="0")
api_environment = models.ForeignKey(APIEnvironment, on_delete=models.CASCADE)
timing_task_status = models.CharField("定时任务是否开启", max_length=50, blank=True, default="", null=True)
starting_time = models.CharField("起始时间", max_length=50, blank=True, default="", null=True)
end_time = models.CharField("截至时间", max_length=50, blank=True, default="", null=True)
time_interval_day = models.IntegerField("间隔时间-天", blank=True, default=0, null=True)
time_interval_minutes = models.IntegerField("间隔时间-分钟", blank=True, default=0, null=True)
time_interval_hours = models.IntegerField("间隔时间-小时", blank=True, default=0, null=True)
time_interval_seconds = models.IntegerField("间隔时间-秒", blank=True, default=0, null=True)
database = models.ForeignKey(APIDatabase, on_delete=models.CASCADE)
api_management = models.ForeignKey(ApiManagement, on_delete=models.CASCADE)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return self.api_test_plan_name
class APITestPlanResult(models.Model):
"""
API测试计划结果表
"""
api_test_result_name = models.CharField("api测试报告名称", max_length=200, blank=False, default="")
api_test_plan = models.ForeignKey(ApiTestPlan, on_delete=models.CASCADE)
api_error_total_number = models.CharField("失败总数", max_length=100, null=True, blank=True)
api_successful_total_number = models.CharField("成功总数", max_length=100, null=True, blank=True)
api_total_number = models.CharField("API总数", max_length=100, null=True, blank=True)
api_environment_id = models.CharField("API环境", max_length=100, null=True, blank=True)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return self.api_test_result_name
class APITestPlanResultAssociated(models.Model):
"""
API测试结果关联表
"""
api_test_case_name = models.CharField("api测试用例名称", max_length=1000, blank=False, default="")
api_test_plan = models.ForeignKey(ApiTestPlan, on_delete=models.CASCADE)
api_result = models.ForeignKey(APITestPlanResult, on_delete=models.CASCADE)
api_error = models.CharField("失败", max_length=100, null=True, blank=True)
api_successful = models.CharField("成功", max_length=100, null=True, blank=True)
abnormal = models.TextField("异常", max_length=50000, null=True, blank=True)
json_extract_variable_conversion = models.TextField("json提取变量转换",
max_length=5000, null=True, blank=True)
api_assertion_results = models.TextField("断言结果", max_length=50000, null=True, blank=True)
api_variable_results = models.TextField("参数提取", max_length=50000, null=True, blank=True)
api_request_results = models.TextField("API请求结果", max_length=500000, null=True, default=None)
api_business_test_name = models.TextField("API业务测试名称", max_length=50000, null=True, blank=True)
api_header = models.TextField("header", max_length=50000, null=True, blank=True)
api_url = models.TextField("请求地址", max_length=50000, null=True, blank=True)
api_body = models.TextField("body", max_length=500000, null=True, blank=True)
update_time = models.DateTimeField(auto_now_add=True)
create_time = models.DateTimeField("创建时间", auto_now_add=True)
def __str__(self):
return self.api_test_case_name
# -*- coding: utf-8 -*-
# @Time : 2021/4/20 14:37
# @Author : wangyinghao
# @FileName: api_test_task.py
# @Software: PyCharm
# from django.db import models
# from automated_main.models.api_automation.api_project import APIProject
# from automated_main.models.api_automation.api_environment import APIEnvironment
# from automated_main.models.api_automation.api_database import APIDatabase
"""
8.19 弃用
"""
# class APITestTask(models.Model):
# """
# API任务表
# """
# api_test_task_name = models.CharField("API测试任务名称", max_length=100, blank=False, default="")
# describe = models.TextField("描述", default="", null=True)
# status = models.IntegerField("状态:", default=0) # 未执行、执行中、执行完成、排队中
# cases = models.TextField("关联API用例", default="")
# api_send_email = models.CharField("API邮件发送", max_length=9999, blank=True, default="", null=True)
# api_send_enterprise_wechat = models.IntegerField("API企业微信发送消息", blank=True, default="0")
# api_environment = models.ForeignKey(APIEnvironment, on_delete=models.CASCADE)
# timing_task_status = models.CharField("定时任务是否开启", max_length=50, blank=True, default="", null=True)
# starting_time = models.CharField("起始时间", max_length=50, blank=True, default="", null=True)
# end_time = models.CharField("截至时间", max_length=50, blank=True, default="", null=True)
# time_interval_day = models.IntegerField("间隔时间-天", blank=True, default=0, null=True)
# time_interval_minutes = models.IntegerField("间隔时间-分钟", blank=True, default=0, null=True)
# time_interval_hours = models.IntegerField("间隔时间-小时", blank=True, default=0, null=True)
# time_interval_seconds = models.IntegerField("间隔时间-秒", blank=True, default=0, null=True)
# database = models.ForeignKey(APIDatabase, on_delete=models.CASCADE)
# api_project = models.ForeignKey(APIProject, on_delete=models.CASCADE)
# update_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_test_task_name
#
#
# class APITestResult(models.Model):
# """
# API测试结果表
# """
# api_test_result_name = models.CharField("api测试报告名称", max_length=200, blank=False, default="")
# api_task = models.ForeignKey(APITestTask, on_delete=models.CASCADE)
# api_error_total_number = models.CharField("失败总数", max_length=100, null=True, blank=True)
# api_successful_total_number = models.CharField("成功总数", max_length=100, null=True, blank=True)
# api_total_number = models.CharField("API总数", max_length=100, null=True, blank=True)
# api_environment_id = models.CharField("API环境", max_length=100, null=True, blank=True)
# update_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_test_result_name
#
#
# class APITestResultAssociated(models.Model):
# """
# API测试结果关联表
# """
# api_test_case_name = models.CharField("api测试用例名称", max_length=100, blank=False, default="")
# api_task = models.ForeignKey(APITestTask, on_delete=models.CASCADE)
# api_result = models.ForeignKey(APITestResult, on_delete=models.CASCADE)
# api_error = models.CharField("失败", max_length=100, null=True, blank=True)
# api_successful = models.CharField("成功", max_length=100, null=True, blank=True)
# abnormal = models.TextField("异常", max_length=5000, null=True, blank=True)
# json_extract_variable_conversion = models.TextField("json提取变量转换",
# max_length=5000, null=True, blank=True)
# api_assertion_results = models.TextField("断言结果", max_length=5000, null=True, blank=True)
# api_variable_results = models.TextField("参数提取", max_length=5000, null=True, blank=True)
# api_request_results = models.JSONField("API请求结果", null=True, default=None)
# api_business_test_name = models.TextField("API业务测试名称", max_length=5000, null=True, blank=True)
# api_header = models.TextField("header", max_length=5000, null=True, blank=True)
# api_url = models.TextField("请求地址", max_length=5000, null=True, blank=True)
# api_body = models.TextField("body", max_length=5000, null=True, blank=True)
# update_time = models.DateTimeField(auto_now_add=True)
# create_time = models.DateTimeField("创建时间", auto_now_add=True)
#
# def __str__(self):
# return self.api_test_case_name
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:10
@Auth : WangYingHao
@File :__init__.py.py
@IDE :PyCharm
"""
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:10
@Auth : WangYingHao
@File :api_business_test_url.py
@IDE :PyCharm
"""
"""
8.19 弃用
"""
# from django.urls import path
# from automated_main.view.api_automation.api_business_test.api_business_test_list_view import \
# ApiBusinessTestListView
# from automated_main.view.api_automation.api_business_test.api_business_test_view import GetApiBusinessTestSelectData,\
# ApiBusinessTestView, ApiBusinessTestDebugView
# urlpatterns = [
# # API业务测试
# path("api/backend/api_business_test/list/<int:api_project_id>/",
# ApiBusinessTestListView.as_view()),
# path("api/backend/api_business_test/get_api_test_business_test_select_data/<int:api_project_id>/",
# GetApiBusinessTestSelectData.as_view()),
# path("api/backend/api_business_test/", ApiBusinessTestView.as_view()),
# path("api/backend/api_business_test/<int:api_business_test_id>/", ApiBusinessTestView.as_view()),
# path("api/backend/api_business_test/api_business_test_debug/", ApiBusinessTestDebugView.as_view()),
# ]
# -*- coding: utf-8 -*-
# @Time : 2021/10/22 9:53
# @Author : wangyinghao
# @File : api_database_url.py
# @Software: PyCharm
from django.urls import path
from automated_main.view.api_automation.api_database.api_database_list_view import ApiDatabaseListView
from automated_main.view.api_automation.api_database.api_database_view import ApiDatabaseView, DatabaseProcessingView
urlpatterns = [
# 获取api数据库列表
path("api/backend/api_database/list/", ApiDatabaseListView.as_view()),
path("api/backend/api_database/", ApiDatabaseView.as_view()),
path("api/backend/api_database/<int:api_database_id>/", ApiDatabaseView.as_view()),
path("api/backend/api_debug_database/", DatabaseProcessingView.as_view()),
]
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:10
@Auth : WangYingHao
@File :api_environment_url.py
@IDE :PyCharm
"""
from django.urls import path
from automated_main.view.api_automation.api_environment.api_environment_list_view import ApiEnvironmentListView
from automated_main.view.api_automation.api_environment.api_environment_view import ApiEnvironmentView
urlpatterns = [
# 获取api环境列表
path("api/backend/api_environment/list/", ApiEnvironmentListView.as_view()),
path("api/backend/api_environment/", ApiEnvironmentView.as_view()),
path("api/backend/api_environment/<int:api_environment_id>/", ApiEnvironmentView.as_view()),
]
# -*- coding: utf-8 -*-
# @Time : 2022/5/24 21:36
# @Author : wangyinghao
# @File : api_management_url.py
# @Software: PyCharm
from django.urls import path
from automated_main.view.api_automation.api_management.api_management_detail_view import ApiManagementView
from automated_main.view.api_automation.api_management.api_management_list_view import ApiManagementListView, ApiManagementSearchView,ApiManagementJudgeView, ApiManagementStructureDataEditView, ApiYaPiInterfaceView, YaPiInterfaceBasicInformationView
from automated_main.view.api_automation.api_management.api_interfaces_case_list_view import ApiInterfacesListView
from automated_main.view.api_automation.api_management.api_interfaces_case_view import ApiInterfacesCaseView, ApiInterfacesCaseDeBugView
urlpatterns = [
# 获取接口服务列表
path("api/backend/api_management/list/", ApiManagementListView.as_view()),
# 变更/获取 单个服务
path("api/backend/api_management/<int:api_management_id>/", ApiManagementView.as_view()),
# 获取接口测试用例列表
path("api/backend/apiInterfacesList/<int:api_server_id>/", ApiInterfacesListView.as_view()),
# 复制用例
path("api/backend/apiInterfacesCopyCase/", ApiInterfacesListView.as_view()),
# 创建接口测试用例
path("api/backend/apiInterfacesCase/", ApiInterfacesCaseView.as_view()),
# 获取接口测试用例
path("api/backend/apiInterfacesCase/<int:api_interfaces_case_id>/", ApiInterfacesCaseView.as_view()),
# 获取调试测试用例 debug
path("api/backend/apiInterfacesCase/debug/", ApiInterfacesCaseDeBugView.as_view()),
# 搜索-服务树行结构
path("api/backend/apiManagementSearch/", ApiManagementSearchView.as_view()),
# 判断 父节点 是否可创建用例(只有用例节点才可创建用例)
path("api/backend/apiManagement/JudgeAddCases/", ApiManagementJudgeView.as_view()),
# tree树结构变更
path("api/backend/apiManagement/ApiManagementStructureDataEdit/", ApiManagementStructureDataEditView.as_view()),
# 获取YAPI接口基础信息
path("api/backend/apiManagement/yaPiInterfaceBasicInformation/", YaPiInterfaceBasicInformationView.as_view()),
# YAPI接口-新增/修改 到tree树
path("api/backend/apiManagement/apiYaPiInterface/", ApiYaPiInterfaceView.as_view()),
]
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:10
@Auth : WangYingHao
@File :api_module_url.py
@IDE :PyCharm
"""
"""
8.19 弃用
"""
# from django.urls import path
# from automated_main.view.api_automation.api_module.api_module_list_view import ApiModuleListView
# from automated_main.view.api_automation.api_module.api_module_view import ApiModuleView
# from automated_main.view.api_automation.api_module.api_module_view import ApiProjectModuleView
# urlpatterns = [
#
# # API模块
# path("api/backend/api_module/list/", ApiModuleListView.as_view()),
# path("api/backend/api_module/", ApiModuleView.as_view()),
# path("api/backend/api_module/<int:api_module_id>/", ApiModuleView.as_view()),
#
# # 获取 单个api项目中包含得所有模块
# path("api/backend/api_project/api_module/<int:api_project_id>/<int:size_page>/<int:page>/", ApiProjectModuleView.as_view()),
# ]
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 15:34
# @Author : wangyinghao
# @Site :
# @File : api_plan_url.py
# @Software: PyCharm
from django.urls import path
from automated_main.view.api_automation.api_test_plan.api_test_plan_view import APITestPlanSuspended, ApiTestPlanView, GetScenariosCaseTree, PerformApiPlan, CheckApiPlanResultList, CheckApiResult, CheckApiResultErrorList
from automated_main.view.api_automation.api_test_plan.api_test_plan_list_view import ApiTestPlanListView
urlpatterns = [
# 测试计划-删除/编辑/获取
path("api/backend/api_test_plan/<int:api_test_plan_id>/", ApiTestPlanView.as_view()),
# 新增测试计划
path("api/backend/api_test_plan/", ApiTestPlanView.as_view()),
# 暂停测试计划
path("api/backend/api_test_plan/suspended/", APITestPlanSuspended.as_view()),
# 获取项目下所有测试计划
path("api/backend/api_test_plan/list/<int:api_management_id>/", ApiTestPlanListView.as_view()),
# 场景用例树结构
path("api/backend/api_test_plan/get_scenarios_case_tree/<int:api_management_id>/", GetScenariosCaseTree.as_view()),
path("api/backend/api_test_plan/post_scenarios_case_tree/<int:api_test_plan_id>/", GetScenariosCaseTree.as_view()),
# API-执行测试计划
path("api/backend/api_test_plan/perform_api_test_plan/<int:api_test_plan_id>/", PerformApiPlan.as_view()),
# API-执行所有测试计划
path("api/backend/api_test_plan/perform_api_test_plan_all/", PerformApiPlan.as_view()),
# 测试计划报告列表
path("api/backend/api_test_plan/check_result_list/<int:api_test_plan_id>/<int:size_page>/<int:page>/",
CheckApiPlanResultList.as_view()),
# API测试计划-查看单独测试计划报告
path("api/backend/api_test_plan/check_result/<int:api_test_result_id>/<int:size_page>/<int:page>/",
CheckApiResult.as_view()),
path("api/backend/api_test_plan/single_check_result/<int:api_test_case_result_id>/", CheckApiResult.as_view()),
path("api/backend/api_test_plan/check_result/<int:api_test_result_id>/", CheckApiResult.as_view()),
# 查看失败报告
path("api/backend/api_test_plan/check_result/error/<int:api_test_result_id>/<int:size_page>/<int:page>/",
CheckApiResultErrorList.as_view()),
]
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:11
@Auth : WangYingHao
@File :api_project_url.py
@IDE :PyCharm
"""
"""
8.19 弃用
"""
# from django.urls import path
# from automated_main.view.api_automation.api_project.api_project_view import ApiProjectView
# from automated_main.view.api_automation.api_project.api_project_list_view import ApiProjectListView
# urlpatterns = [
#
# # API项目
# path("api/backend/api_project/", ApiProjectView.as_view()),
# path("api/backend/api_project/<int:api_project_id>/", ApiProjectView.as_view()),
# path("api/backend/api_project/list/", ApiProjectListView.as_view()),
# ]
# -*- coding: utf-8 -*-
# @Time : 2022/7/19 13:47
# @Author : wangyinghao
# @Site :
# @File : api_scenarios_case_url.py
# @Software: PyCharm
from django.urls import path
from automated_main.view.api_automation.api_scenario_use_case.api_scenarios_case_list_view import ApiScenariosCaseListView, InterfacesProjectListView, ServiceModuleInterfacesCaseRelationshipView, ApiScenariosCaseCopyView
from automated_main.view.api_automation.api_scenario_use_case.api_scenarios_case_view import ApiScenariosCaseView, ApiScenariosCaseGetView, ApiScenariosCaseDebugView
urlpatterns = [
# 获取接口测试用例列表 4级目录 tree树
path("api/backend/api_scenarios_case/list/", ApiScenariosCaseListView.as_view()),
# 获取接口项目列表
path("api/backend/InterfacesProjectList/list/", InterfacesProjectListView.as_view()),
# 创建场景用例
path("api/backend/api_scenarios_case/", ApiScenariosCaseView.as_view()),
# 删除/编辑 场景接口测试用例
path("api/backend/api_scenarios_case/<int:scenarios_case_id>/", ApiScenariosCaseView.as_view()),
# 获取单个场景接口测试用例-组装
path("api/backend/api_single_scenarios_case/<int:scenarios_case_id>/", ApiScenariosCaseGetView.as_view()),
# 获取场景接口测试用例列表
path("api/backend/interfaces_scenarios_case/list/<int:api_management_id>/", ApiScenariosCaseView.as_view()),
# 场景接口用例debug
path("api/backend/interfaces_scenarios_case/interfaces_scenarios_case_debug/", ApiScenariosCaseDebugView.as_view()),
# 场景接口-服务-模块-接口-用例 关系
path("api/backend/interfaces_scenarios_case/ServiceModuleInterfacesCaseRelationship/", ServiceModuleInterfacesCaseRelationshipView.as_view()),
# Copy-复制 场景用例
path("api/backend/copy_interfaces_scenarios_case/", ApiScenariosCaseCopyView.as_view()),
]
# -*- coding: utf-8 -*-
"""
@Time : 2021/6/21 11:11
@Auth : WangYingHao
@File :api_test_case_url.py
@IDE :PyCharm
"""
"""
8.19 弃用
"""
# from django.urls import path
# from automated_main.view.api_automation.api_test_case.api_test_case_list_view import ApiTestCaseListView
# from automated_main.view.api_automation.api_test_case.api_test_case_view import ApiTestCaseView, ApiTestCaseDeBugView, UploadTestCases, DownloadApiCaseTemplate
# urlpatterns = [
# # API测试用例
# path("api/backend/api_test_case/list/<int:api_module_id>/", ApiTestCaseListView.as_view()),
# path("api/backend/api_test_case/<int:api_test_case_id>/", ApiTestCaseView.as_view()),
# path("api/backend/api_test_case/", ApiTestCaseView.as_view()),
# path("api/backend/api_test_case/debug/", ApiTestCaseDeBugView.as_view()),
# # 上传API测试用例
# path("api/backend/api_test_case/upload_test_cases/", UploadTestCases.as_view(), name="upload"),
#
# # 导入API测试用例
# path("api/backend/api_test_case/upload_api_case_import/", UploadTestCases.as_view()),
#
# # 下载web脚本模板
# path("api/backend/api_test_case/api_test_case_template/download_api_case_template/",
# DownloadApiCaseTemplate.as_view()),
# ]
# # -*- coding: utf-8 -*-
# """
# @Time : 2021/6/21 11:11
# @Auth : WangYingHao
# @File :api_test_task_url.py
# @IDE :PyCharm
#
# """
# from django.urls import path
# """
# 8.19 弃用
# """
# # from automated_main.view.api_automation.api_test_task.api_test_task_list_view import ApiTestTaskListView
# from automated_main.view.api_automation.api_test_task.api_test_task_view import ApiTestTaskView, APITestTaskSuspended, GetApiCaseTree, CheckApiResultList, CheckApiResult, PerformApiTask, CheckApiResultErrorList, ApiServiceChangesTask
# from automated_main.view.api_automation.api_data_synchronization.api_data_synchronization_view import ApiDataSynchronization, ApiScenarioSynchronization
#
#
# urlpatterns = [
# # API任务管理
#
# # path("api/backend/api_test_task/list/<int:api_project_id>/", ApiTestTaskListView.as_view()),
# path("api/backend/api_test_task/<int:api_test_task_id>/", ApiTestTaskView.as_view()),
# path("api/backend/api_test_task/", ApiTestTaskView.as_view()),
# path("api/backend/api_test_task/suspended/", APITestTaskSuspended.as_view()),
#
# path("api/backend/api_test_task/get_api_case_tree/<int:api_project_id>/", GetApiCaseTree.as_view()),
# path("api/backend/api_test_task/get_api_case_tree/<int:api_test_task_id>/", GetApiCaseTree.as_view()),
#
# # API任务管理-查看报告列表
# path("api/backend/api_test_task/check_result_list/<int:api_test_task_id>/<int:size_page>/<int:page>/", CheckApiResultList.as_view()),
#
# # API任务管理-查看单独测试报告
# path("api/backend/api_test_task/check_result/<int:api_test_result_id>/<int:size_page>/<int:page>/", CheckApiResult.as_view()),
# path("api/backend/api_test_task/check_result/<int:api_test_result_id>/", CheckApiResult.as_view()),
# path("api/backend/api_test_task/single_check_result/<int:api_test_case_result_id>/", CheckApiResult.as_view()),
# # 查看失败报告
# path("api/backend/api_test_task/check_result/error/<int:api_test_result_id>/<int:size_page>/<int:page>/", CheckApiResultErrorList.as_view()),
#
# # API任务管理-执行任务
# path("api/backend/api_test_task/perform_api_task/<int:api_test_task_id>/", PerformApiTask.as_view()),
#
# # API任务管理-执行所有任务
# path("api/backend/api_test_task/perform_all_api_task/", PerformApiTask.as_view()),
#
# # API任务管理-执行服务有更改的接口
# path("api/backend/api_test_task/api_service_changes_task/", ApiServiceChangesTask.as_view()),
#
# # API数据同步-8.4弃用
# path("api/backend/apiDataSynchronization/", ApiDataSynchronization.as_view()),
#
# # API场景数据同步-8.5弃用
# path("api/backend/apiScenarioDataSynchronization/", ApiScenarioSynchronization.as_view()),
#
# ]
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:39
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/4/14 18:55
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/4/14 18:59
# @Author : wangyinghao
# @FileName: api_business_test_list_view.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.views.decorators.csrf import csrf_exempt
# from django.views.generic import View
# from automated_main.utils.http_format import response_success
# from automated_main.models.api_automation.api_business_test import ApiBusinessTest
# import arrow
# class ApiBusinessTestListView(View):
# def get(self, request, api_project_id, *args, **kwargs):
# """
# 代表获取该项目下所有API业务测试
# :param request:
# :param api_project_id: api项目id
# :param args:
# :param kwargs:
# :return:
# """
#
# api_business_case = ApiBusinessTest.objects.filter(api_project_id=api_project_id).order_by('-id')
# api_business_case_list = []
#
# for api_business_cases in api_business_case:
# ui_test_cases_dict = {
# "id": api_business_cases.id,
# "api_business_test_name": api_business_cases.api_business_test_name,
# "api_project_id": api_business_cases.api_project.id,
# "api_project_name": api_business_cases.api_project.api_project_name,
# "api_business_test_describe": api_business_cases.api_business_test_describe,
# "update_time": arrow.get(str(api_business_cases.updata_time)).format('YYYY-MM-DD HH:mm:ss'),
# "create_time": arrow.get(str(api_business_cases.create_time)).format('YYYY-MM-DD HH:mm:ss')
# }
# api_business_case_list.append(ui_test_cases_dict)
#
# return response_success(api_business_case_list)
# -*- coding: utf-8 -*-
# @Time : 2021/4/14 18:59
# @Author : wangyinghao
# @FileName: api_business_test_view.py
# @Software: PyCharm
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View
import json
import ast
import re
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_project import APIProject
from automated_main.models.api_automation.api_module import APIModule
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_business_test import ApiBusinessTest, ApiBusinessTestAssociated
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.handle_db import HandleDB
from automated_main.form.api_business_test import ApiBusinessTestForm
from automated_main.utils.api_utils import RegularMatch, InterfaceRequest, ExtractParameters
from automated_main.models.api_automation.api_test_case import ApiTestCase, ApiParameterExtraction, ApiParameterData
import logging
logger = logging.getLogger('django')
class GetApiBusinessTestSelectData(View):
def get(self, request, api_project_id, *args, **kwargs):
"""
获取api项目---模块---测试用例
:param request:
:param api_project_id: Api项目id
:param args:
:param kwargs:
:return:
"""
api_projects = APIProject.objects.filter(id=api_project_id)
data_list = []
for api_project in api_projects:
project_dict = {
"project_id": api_project.id,
"api_project_name": api_project.api_project_name
}
api_modules = APIModule.objects.filter(api_project_id=api_project.id)
api_module_list = []
for api_module in api_modules:
api_test_cases = ApiTestCase.objects.filter(api_module_id=api_module.id)
api_test_case_list = []
for api_test_case in api_test_cases:
api_test_case_list.append({
"api_test_case_id": api_test_case.id,
"api_test_case_name": api_test_case.api_test_case_name,
})
api_module_list.append({
"api_module_id": api_module.id,
"api_module_name": api_module.api_module_name,
"api_test_case_list": api_test_case_list,
})
project_dict["module_list"] = api_module_list
data_list.append(project_dict)
return response_success(data_list)
class ApiBusinessTestView(View):
def delete(self, request, api_business_test_id, *args, **kwargs):
"""
代表删除API业务测试
:param request:
:param api_business_test_id: 业务测试id
:param args:
:param kwargs:
:return:
"""
ApiBusinessTest.objects.get(id=api_business_test_id).delete()
return response_success("删除API业务测试成功")
def get(self, request, api_business_test_id, *args, **kwargs):
"""
获取单独API业务测试
:param request:
:param api_business_test_id: 业务测试ID
:param args:
:param kwargs:
:return:
"""
api_business_test = ApiBusinessTest.objects.get(id=api_business_test_id)
api_business_test_associated = ApiBusinessTestAssociated.objects.filter(bid_id=api_business_test_id)
if api_business_test is None:
return response_success()
else:
api_business_test_data_list = []
for api_business_test_associateds in api_business_test_associated:
api_business_test_dict = {
"api_module_id": api_business_test_associateds.api_module_id,
"api_test_case_id": api_business_test_associateds.api_test_case_id,
"steps": int(api_business_test_associateds.case_steps),
}
api_business_test_data_list.append(api_business_test_dict)
api_business_test_data_list_sorting = sorted(api_business_test_data_list, key=lambda x: x['steps'])
return response_success({"api_business_test_name": api_business_test.api_business_test_name,
"api_project_id": api_business_test.api_project_id,
"api_business_test_describe": api_business_test.api_business_test_describe,
"api_business_test_data": api_business_test_data_list_sorting})
def post(self, request, api_business_test_id, *args, **kwargs):
"""
编辑API业务测试
:param request:
:param api_business_test_id:
:param args:
:param kwargs:
:return:
"""
api_business_test = ApiBusinessTest.objects.get(id=api_business_test_id)
if api_business_test is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiBusinessTestForm(data)
api_business_test.api_business_test_name = data['api_business_test_name']
api_business_test.api_project.id = data['api_project_id']
api_business_test.id = data['api_business_test_id']
api_business_test.api_business_test_describe = data['api_business_test_describe']
api_business_test.save()
ApiBusinessTestAssociated.objects.filter(bid_id=api_business_test_id).delete()
if form.is_valid():
for i in data["api_business_test_data"]:
api_module_id = (i['api_module_id'])
api_test_case_id = (i['api_test_case_id'])
case_steps = (i['steps'])
ApiBusinessTestAssociated.objects.create(bid_id=api_business_test_id, api_module_id=api_module_id,
api_test_case_id=api_test_case_id, case_steps=case_steps)
return response_success("编辑API业务测试")
else:
raise MyException()
def put(self, request, *args, **kwargs):
"""
创建API业务测试
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiBusinessTestForm(data)
if form.is_valid():
api_business_test = ApiBusinessTest.objects.create(**form.cleaned_data)
api_business_test_id = api_business_test.id
for i in data["api_business_test_data"]:
api_module_id = (i['api_module_id'])
api_test_case_id = (i['api_test_case_id'])
case_steps = (i['steps'])
ApiBusinessTestAssociated.objects.create(bid_id=api_business_test_id, api_module_id=api_module_id,
api_test_case_id=api_test_case_id, case_steps=case_steps)
return response_success("创建API业务测试用例成功")
else:
raise MyException()
class ApiBusinessTestDebugView(View):
def post(self, request, *args, **kwargs):
"""
API业务测试DEBUG
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
for case in data['api_business_test_data']:
test_case = ApiTestCase.objects.get(id=case['api_test_case_id'])
api_environment = APIEnvironment.objects.get(id=data['environment'])
# 请求地址
api_url = api_environment.api_title + test_case.api_url
api_url = RegularMatch(api_url, data['environment'])
if api_url[0] == "该变量数据库未找到":
return response_failed("4000", str(api_url[0] + api_url[1]))
api_headers = RegularMatch(test_case.api_headers, data['environment'])
if api_headers[0] == "该变量数据库未找到":
return response_failed("4000", str(api_headers[0] + api_headers[1]))
json_header = api_headers.replace("\'", "\"")
if test_case.api_headers == '':
header = test_case.api_headers
else:
try:
header = json.loads(json_header)
except json.decoder.JSONDecodeError:
return response_failed('30000', "header类型错误,用例名称: " + str(test_case.api_test_case_name))
logger.info(json_header)
api_parameter_body = RegularMatch(test_case.api_parameter_body, data['environment'])
if api_parameter_body[0] == "该变量数据库未找到":
return response_failed('40000', "该变量数据库未找到,用例名称: " + str(test_case.api_test_case_name) + "\n" + "变量值:" +
str(api_parameter_body[0] + api_parameter_body[1]))
json_par = api_parameter_body.replace("\'", "\"")
if api_parameter_body == '':
payload = api_parameter_body
logger.info(payload)
else:
try:
payload = json.loads(json_par)
logger.info(payload)
except json.decoder.JSONDecodeError:
return response_failed('30000', "参数类型错误,用例名称: " + str(test_case.api_test_case_name))
# Params参数
parameter_data = ApiParameterData.objects.filter(api_test_case_id=case['api_test_case_id'])
api_parameter_dict = {}
for api_parameters in parameter_data:
if api_parameters.api_must_parameter == "true":
api_parameter_dict.update(
{api_parameters.api_parameter_name: api_parameters.api_parameter_value})
else:
pass
if api_parameter_dict == {}:
api_parameter_data = {}
else:
api_parameter_data = RegularMatch(str(api_parameter_dict), data['environment'])
if api_parameter_data == {}:
data_payload = api_parameter_data
logger.info(data_payload)
else:
try:
data_payload = ast.literal_eval(api_parameter_data)
except json.decoder.JSONDecodeError:
return response_failed("30000", "Parameter参数类型错误" + api_parameter_data)
r = InterfaceRequest(str(test_case.api_method), str(test_case.api_parameter_types),
api_url, header, payload, data_payload)
if r == "请求超时":
return response_failed('30000', "接口请求超时:" + str(test_case.api_test_case_name))
try:
response_message = r.json()
except json.decoder.JSONDecodeError:
return response_failed('30000', "接口返回结果类型错误非JSON格式:" + str(test_case.api_test_case_name))
# 断言
if test_case.api_assert_type == '':
result = "断言内容为空"
logger.error(result)
elif test_case.api_assert_type == 1:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(test_case.api_assert_text.split())
assert r_text_data in r_text_test
except Exception as e:
result = "断言失败: 响应内容中未包含 断言内容,断言内容: %s ,响应内容:%s" % (r_text_data, r_text_test)
logger.error(result + str(e))
return response_failed('30000', "断言失败,用例名称: " + str(test_case.api_test_case_name) + "\n" +
"断言结果:" + result)
elif test_case.api_assert_type == 2:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(test_case.api_assert_text.split())
assert r_text_data == r_text_test
except Exception as e:
result = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (r_text_data, r_text_test)
logger.error(result, e)
return response_failed('30000', "断言失败,用例名称: " + str(test_case.api_test_case_name) + "\n" +
"断言结果:" + result)
elif test_case.api_assert_type == 3:
database = APIDatabase.objects.get(id=test_case.dataBase_id)
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
sql = data['database_sql']
count = db.get_count(sql)
db.close()
if str(count) == str(test_case.api_assert_text):
result = '断言成功'
logger.error(result)
else:
result = '断言失败,查询的数据是: %s' % str(count)
logger.error(result)
return response_failed('30000', "断言失败,用例名称: " + str(test_case.api_test_case_name) + "\n" +
"断言结果:" + result)
elif test_case.api_assert_type == 4:
try:
assert test_case.api_assert_text == str(r.status_code)
result = "断言成功"
except Exception as e:
result = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (test_case.api_assert_text, str(r.status_code))
logger.error(result, e)
return response_failed('30000', "断言失败,用例名称: " + str(test_case.api_test_case_name) + "\n" +
"断言结果:" + result)
parameter_extraction = ApiParameterExtraction.objects.filter(api_test_case_id=case['api_test_case_id'])
if parameter_extraction == "" or None:
pass
else:
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
logger.info('json转换失败(变量):' + str(e))
pass
for parameter_extractions in parameter_extraction:
v_text = parameter_extractions.api_value_variable.split(".")
try:
api_results = ExtractParameters(v_text, api_result)
api_parameter_extraction = ApiParameterExtraction.objects.get(
api_key_variable=str(parameter_extractions.api_key_variable))
api_parameter_extraction.api_variable_results = str(api_results)
api_parameter_extraction.save()
except Exception as e:
logger.info('参数提取失败' + str(e))
return response_failed('30000', "参数提取失败,用例名称:" +
str(test_case.api_test_case_name) + '\n' + "异常信息:" + str(e))
return response_success("调试成功")
# -*- coding: utf-8 -*-
# @Time : 2022/7/25 10:39
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2022/7/25 10:40
# @Author : wangyinghao
# @Site :
# @File : api_data_synchronization_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_project import APIProject
from automated_main.models.api_automation.api_test_task import APITestResult, APITestResultAssociated, APITestTask
from automated_main.models.api_automation.api_test_plan import ApiTestPlan, APITestPlanResult, \
APITestPlanResultAssociated
from automated_main.models.api_automation.api_business_test import ApiBusinessTest, ApiBusinessTestAssociated
from automated_main.models.api_automation.api_module import APIModule
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.models.api_automation.api_test_case import ApiTestCase, ApiParameterExtraction, ApiParameterData
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase, \
ApiInterfacesParameterExtraction, ApiInterfacesParameterData
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCase, ApiScenariosCaseAssociated
class ApiDataSynchronization(View):
# def post(self, request, *args, **kwargs):
# """
# 数据同步 创建项目、创建测试用例
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
# project = APIProject.objects.all()
#
# for pr in project:
# management = ApiManagement.objects.create(name=pr.api_project_name, description=pr.api_project_name)
#
# module = APIModule.objects.filter(api_project_id=pr.id)
# for m in module:
# Api_m = ApiManagement.objects.create(name=m.api_module_name, description=m.api_module_name,
# parent=management.id)
# for m2 in module:
# Api_m2 = ApiManagement.objects.create(name=m.api_module_name, description=m2.api_module_name,
# parent=Api_m.id)
# case_data = ApiTestCase.objects.filter(api_module_id=m2.id)
#
# for case in case_data:
# case_node = ApiManagement.objects.create(name=case.api_test_case_name,
# description=case.api_test_case_name,
# parent=Api_m2.id)
#
# api = ApiInterfacesCase.objects.create(
# api_interfaces_case_name=case.api_test_case_name,
# api_documentation=case.api_documentation,
# api_management_id=case_node.id,
# api_environment_id=case.api_environment_id,
# api_method=case.api_method,
# api_url=case.api_url,
# api_parameter_types=case.api_parameter_types,
# api_headers=case.api_headers,
# api_parameter_body=case.api_parameter_body,
# api_assert_type=case.api_assert_type,
# dataBase_id=case.dataBase_id,
# database_sql=case.database_sql,
# api_assert_text=case.api_assert_text,
# ) if case.api_assert_text else None
#
# extraction = ApiParameterExtraction.objects.filter(api_test_case_id=case.id)
#
# for ex in extraction:
# ApiInterfacesParameterExtraction.objects.create(
# api_test_case_id=api.id,
# api_variable_results=ex.api_variable_results,
# api_value_variable=ex.api_value_variable,
# api_key_variable=ex.api_key_variable
# )
#
# parameter_data = ApiParameterData.objects.filter(api_test_case_id=case.id)
#
# for parameter in parameter_data:
# ApiInterfacesParameterData.objects.create(
# api_test_case_id=api.id,
# api_parameter_name=parameter.api_parameter_name,
# api_must_parameter=parameter.api_must_parameter,
# api_parameter_value=parameter.api_parameter_value,
# api_field_describe=parameter.api_field_describe,
# )
#
# return response_success()
def get(self, request, *args, **kwargs):
"""
数据同步 同步项目接口
:param request:
:param args:
:param kwargs:
:return:
"""
project_data = APIProject.objects.all()
for project in project_data:
ApiManagement.objects.create(name=project.api_project_name, description=project.api_project_name)
return response_success()
def post(self, request, *args, **kwargs):
"""
数据同步,同步服务名称 tree
仅限以下两个服务
开放平台/启客_Frequent_API
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
module_data = APIModule.objects.filter(api_project_id=data['project_id'])
api_management_data = ApiManagement.objects.get(name=data['management_name'])
for module in module_data:
ApiManagement.objects.create(name=module.api_module_name, description=module.api_module_name,
parent=api_management_data.id)
return response_success()
def put(self, request, *args, **kwargs):
"""
数据同步,同步服务名称 tree
仅限以下两个服务
数据中心/启魔方APP/招标云/SCRM
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
case_data = ApiTestCase.objects.filter(api_module_id=data['module_id'])
api_management_data = ApiManagement.objects.get(name=data['management_name'])
for case in case_data:
api_tree_data = ApiManagement.objects.create(name=case.api_test_case_name,
description=case.api_test_case_name,
parent=api_management_data.id)
api = ApiInterfacesCase.objects.create(
api_interfaces_case_name=case.api_test_case_name,
api_documentation=case.api_documentation,
api_management_id=api_tree_data.id,
api_environment_id=case.api_environment_id,
api_method=case.api_method,
api_url=case.api_url,
api_parameter_types=case.api_parameter_types,
api_headers=case.api_headers,
api_parameter_body=case.api_parameter_body,
api_assert_type=case.api_assert_type,
dataBase_id=case.dataBase_id,
database_sql=case.database_sql,
api_assert_text=case.api_assert_text,
) if case.api_assert_text else None
extraction = ApiParameterExtraction.objects.filter(api_test_case_id=case.id)
for ex in extraction:
ApiInterfacesParameterExtraction.objects.create(
api_test_case_id=api.id,
api_variable_results=ex.api_variable_results,
api_value_variable=ex.api_value_variable,
api_key_variable=ex.api_key_variable
)
parameter_data = ApiParameterData.objects.filter(api_test_case_id=case.id)
for parameter in parameter_data:
ApiInterfacesParameterData.objects.create(
api_test_case_id=api.id,
api_parameter_name=parameter.api_parameter_name,
api_must_parameter=parameter.api_must_parameter,
api_parameter_value=parameter.api_parameter_value,
api_field_describe=parameter.api_field_describe,
)
return response_success()
class ApiScenarioSynchronization(View):
def post(self, request, *args, **kwargs):
"""
业务场景数据同步
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
business_test_data = ApiBusinessTest.objects.filter(api_project_id=data['api_project_id'])
for business_test in business_test_data:
api_management = ApiManagement.objects.get(name=business_test.api_project.api_project_name)
api_scenarios_case = ApiScenariosCase.objects.create(
api_scenarios_case_name=business_test.api_business_test_name,
api_scenarios_case_describe=business_test.api_business_test_describe,
api_management_id=api_management.id
)
api_business_test_associated_data = ApiBusinessTestAssociated.objects.filter(bid_id=business_test.id)
for api_business_test_associated in api_business_test_associated_data:
api_test_case = ApiTestCase.objects.get(id=api_business_test_associated.api_test_case_id)
api_module = APIModule.objects.get(id=api_test_case.api_module_id)
if api_module.api_project_id == data['api_project_id']:
api_interfaces_case_data = ApiInterfacesCase.objects.filter(
api_interfaces_case_name=api_test_case.api_test_case_name)
for api_interfaces_case in api_interfaces_case_data:
management_A = ApiManagement.objects.get(id=api_interfaces_case.api_management_id)
management_B = ApiManagement.objects.get(id=management_A.parent)
management_C = ApiManagement.objects.get(id=management_B.parent)
if management_C.parent == 0:
pass
else:
management_D = ApiManagement.objects.get(id=management_C.parent)
if management_D.name == business_test.api_project.api_project_name:
ApiScenariosCaseAssociated.objects.create(sid_id=api_scenarios_case.id,
case_steps=api_business_test_associated.case_steps,
interfaces_case_id=api_interfaces_case.id)
return response_success()
def put(self, request, *args, **kwargs):
"""
同步接口测试报告
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
api_test_result_data = APITestResult.objects.filter(api_task_id=data['api_task_id'])
task = APITestTask.objects.get(id=data['api_task_id'])
plan = ApiTestPlan.objects.get(api_test_plan_name=task.api_test_task_name)
for api_test_result in api_test_result_data:
plan_result = APITestPlanResult.objects.create(api_test_result_name=api_test_result.api_test_result_name,
api_test_plan_id=plan.id,
api_error_total_number=api_test_result.api_error_total_number,
api_successful_total_number=api_test_result.api_successful_total_number,
api_total_number=api_test_result.api_total_number,
api_environment_id=api_test_result.api_environment_id
)
associated_data = APITestResultAssociated.objects.filter(api_result_id=api_test_result.id)
for associated in associated_data:
APITestPlanResultAssociated.objects.create(
api_test_case_name=associated.api_test_case_name,
api_test_plan_id=plan.id,
api_result_id=plan_result.id,
api_error=associated.api_error,
api_successful=associated.api_successful,
abnormal=associated.abnormal,
json_extract_variable_conversion=associated.json_extract_variable_conversion,
api_assertion_results=associated.api_assertion_results,
api_variable_results=associated.api_variable_results,
api_request_results=associated.api_request_results,
api_business_test_name=associated.api_business_test_name,
api_header=associated.api_header,
api_url=associated.api_url,
api_body=associated.api_body
)
return response_success()
# -*- coding: utf-8 -*-
# @Time : 2021/10/21 17:05
# @Author : wangyinghao
# @File : api_database_list_view.py
# @Software: PyCharm
from django.views.generic import View
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_database import APIDatabase
import arrow
class ApiDatabaseListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取所有Api数据库列表
:param request:
:param args:
:param kwargs:
:return:
"""
api_database = APIDatabase.objects.all()
api_database_list = []
for api_databases in api_database:
api_database_dict = {
"id": api_databases.id,
"api_database_title": api_databases.api_database_title,
"api_host": api_databases.api_host,
"user": api_databases.user,
"password": api_databases.password,
"database": api_databases.database,
"updata_time": arrow.get(str(api_databases.updata_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_databases.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_database_list.append(api_database_dict)
return response_success(api_database_list)
# -*- coding: utf-8 -*-
# @Time : 2021/10/21 17:24
# @Author : wangyinghao
# @File : api_database_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.form.api_database import ApiDatabaseForm
from automated_main.utils.handle_db import HandleDB
class ApiDatabaseView(View):
def get(self, request, api_database_id, *args, **kwargs):
"""
代表获取单个API数据库
:param request:
:param api_database_id:数据库的id
:param args:
:param kwargs:
:return:
"""
api_database = APIDatabase.objects.filter(id=api_database_id).first()
if api_database is None:
return response_success()
else:
return response_success(model_to_dict(api_database))
def post(self, request, api_database_id, *args, **kwargs):
"""
代表更改API数据库
:param request:
:param api_database_id:
:param args:
:param kwargs:
:return:
"""
api_database = APIDatabase.objects.filter(id=api_database_id).first()
if api_database is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiDatabaseForm(data)
if form.is_valid():
APIDatabase.objects.filter(id=api_database_id).update(**form.cleaned_data)
return response_success("编辑成功")
else:
raise MyException()
def delete(self, request, api_database_id, *args, **kwargs):
"""
代表删除单独API数据库
:param request:
:param api_database_id: API数据库ID
:param args:
:param kwargs:
:return:
"""
APIDatabase.objects.filter(id=api_database_id).delete()
return response_success("删除成功")
def put(self, request, *args, **kwargs):
"""
代表创建API数据库
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiDatabaseForm(data)
if form.is_valid():
APIDatabase.objects.create(**form.cleaned_data)
return response_success("创建成功")
else:
raise MyException(message="创建失败")
class DatabaseProcessingView(View):
def post(self, request, *args, **kwargs):
"""
连接数据库
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
db = HandleDB(data['api_host'], int(data['api_port']), data['user'], data['password'], data['database'])
sql = 'SELECT VERSION()'
try:
db.execution_results(sql)
db.close()
return response_success("调试成功")
except Exception as e:
print(e)
pass
return MyException(40000, message="调试失败")
# -*- coding: utf-8 -*-
# @Time : 2021/3/25 15:27
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/3/25 15:27
# @Author : wangyinghao
# @FileName: api_environment_list_view.py
# @Software: PyCharm
from django.views.generic import View
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_environment import APIEnvironment
import arrow
class ApiEnvironmentListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取所有Api环境列表
:param request:
:param args:
:param kwargs:
:return:
"""
api_environment = APIEnvironment.objects.all().order_by('-id')
api_environment_list = []
for api_environments in api_environment:
api_environment_dict = {
"id": api_environments.id,
"api_environment_name": api_environments.api_environment_name,
"api_title": api_environments.api_title,
"api_environment_describe": api_environments.api_environment_describe,
"update_time": arrow.get(str(api_environments.update_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_environments.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_environment_list.append(api_environment_dict)
return response_success(api_environment_list)
# -*- coding: utf-8 -*-
# @Time : 2021/3/25 15:28
# @Author : wangyinghao
# @FileName: api_environment_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_environment import APIGlobalVariable
from automated_main.form.api_environment import ApiEnvironmentForm
class ApiEnvironmentView(View):
def get(self, request, api_environment_id, *args, **kwargs):
"""
代表获取单个API环境
:param request:
:param api_environment_id:
:param args:
:param kwargs:
:return:
"""
api_environment = APIEnvironment.objects.filter(id=api_environment_id).first()
api_environment_data = model_to_dict(api_environment)
api_global_variable = APIGlobalVariable.objects.filter(api_environment_id=api_environment_id)
global_variable_list = []
if api_global_variable.count() == 0:
global_variable_dict = {
"api_global_variable_name": "",
"api_global_variable_value": "",
"api_global_variable_describe": ""
}
global_variable_list.append(global_variable_dict)
api_environment_data["global_variable"] = global_variable_list
else:
for global_variable in api_global_variable:
global_variable_dict = {
"api_global_variable_name": global_variable.api_global_variable_name,
"api_global_variable_value": global_variable.api_global_variable_value,
"api_global_variable_describe": global_variable.api_global_variable_describe
}
global_variable_list.append(global_variable_dict)
api_environment_data["global_variable"] = global_variable_list
if api_environment is None:
return response_success()
else:
return response_success(api_environment_data)
def post(self, request, api_environment_id, *args, **kwargs):
"""
代表更改API环境
:param request:
:param api_environment_id:
:param args:
:param kwargs:
:return:
"""
api_environment = APIEnvironment.objects.filter(id=api_environment_id).first()
if api_environment is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiEnvironmentForm(data)
if form.is_valid():
APIEnvironment.objects.filter(id=api_environment_id).update(**form.cleaned_data)
if APIGlobalVariable.objects.filter(api_environment_id=api_environment_id).count() >= 0:
APIGlobalVariable.objects.filter(api_environment_id=api_environment_id).delete()
for global_variable in data['global_variable_data']:
APIGlobalVariable.objects.create(
api_environment_id=api_environment_id,
api_global_variable_name=global_variable['api_global_variable_name'],
api_global_variable_value=global_variable['api_global_variable_value'],
api_global_variable_describe=global_variable['api_global_variable_describe'],
)
return response_success("编辑API环境成功")
else:
raise MyException()
def delete(self, request, api_environment_id, *args, **kwargs):
"""
代表删除单独API环境
:param request:
:param api_environment_id: API环境ID
:param args:
:param kwargs:
:return:
"""
APIEnvironment.objects.filter(id=api_environment_id).delete()
return response_success("删除API环境成功")
def put(self, request, *args, **kwargs):
"""
代表创建API环境
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiEnvironmentForm(data)
if form.is_valid():
api_environment = APIEnvironment.objects.create(**form.cleaned_data)
api_environment.save()
if APIGlobalVariable.objects.filter(api_environment_id=api_environment.id).count() >= 0:
APIGlobalVariable.objects.filter(api_environment_id=api_environment.id).delete()
for global_variable in data['global_variable_data']:
APIGlobalVariable.objects.create(
api_environment_id=api_environment.id,
api_global_variable_name=global_variable['api_global_variable_name'],
api_global_variable_value=global_variable['api_global_variable_value'],
api_global_variable_describe=global_variable['api_global_variable_describe'],
)
return response_success("创建成功")
else:
raise MyException(message="创建失败")
# -*- coding: utf-8 -*-
# @Time : 2022/5/24 21:29
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2022/7/5 14:00
# @Author : wangyinghao
# @Site :
# @File : api_interfaces_case_list_view.py
# @Software: PyCharm
import datetime
from django.views.generic import View
import json
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase, ApiInterfacesParameterData
from automated_main.utils.api_management_utils import ApiManagementUtils
from automated_main.models.api_automation.api_management import ApiManagement
import arrow
class ApiInterfacesListView(View):
def get(self, request, api_server_id, *args, **kwargs):
"""
获取测试用例列表
:param api_server_id: api服务id
:param request:
:param args:
:param kwargs:
:return:
"""
# api_management_id_list = ApiManagementUtils.get_interfaces_case_recursion(api_server_id)
# api_interfaces_cases_list = []
# for api_management_id in api_management_id_list:
# api_interfaces_cases = ApiInterfacesCase.objects.filter(api_management_id=api_management_id)
#
# for interfaces_cases in api_interfaces_cases:
# api_interfaces_cases_dict = {
# "id": interfaces_cases.id,
# "api_interfaces_case_name": interfaces_cases.api_interfaces_case_name,
# "api_test_case_url": interfaces_cases.api_url,
# "api_method": interfaces_cases.api_method,
# "api_documentation": interfaces_cases.api_documentation,
# "update_time": arrow.get(str(interfaces_cases.update_time)).format('YYYY-MM-DD HH:mm:ss'),
# "create_time": arrow.get(str(interfaces_cases.create_time)).format('YYYY-MM-DD HH:mm:ss'),
# }
#
# api_interfaces_cases_list.append(api_interfaces_cases_dict)
# return response_success(api_interfaces_cases_list)
api_interfaces_cases_list = []
api_management_data = ApiManagement.objects.filter(id=api_server_id)
for api_management in api_management_data:
api_management_data_a = ApiManagement.objects.filter(parent=api_management.id)
api_interfaces_cases_list.append(api_management.id)
for api_management_a in api_management_data_a:
api_interfaces_cases_list.append(api_management_a.id)
api_management_data_b = ApiManagement.objects.filter(parent=api_management_a.id)
for api_management_b in api_management_data_b:
api_interfaces_cases_list.append(api_management_b.id)
api_interfaces_cases_data_list = []
for api_management_id in api_interfaces_cases_list:
api_interfaces_cases = ApiInterfacesCase.objects.filter(api_management_id=api_management_id)
for interfaces_cases in api_interfaces_cases:
api_interfaces_cases_dict = {
"id": interfaces_cases.id,
"api_interfaces_case_name": interfaces_cases.api_interfaces_case_name,
"api_test_case_url": interfaces_cases.api_url,
"api_method": interfaces_cases.api_method,
"api_documentation": interfaces_cases.api_documentation,
"update_time": arrow.get(str(interfaces_cases.update_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(interfaces_cases.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_interfaces_cases_data_list.append(api_interfaces_cases_dict)
return response_success(api_interfaces_cases_data_list)
def post(self, request, *args, **kwargs):
"""
复制用例
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
if params == {}:
pass
else:
api_case_data = ApiInterfacesCase.objects.filter(id=params['case_id'])
for api_case in api_case_data:
copy_api_interfaces_case = ApiInterfacesCase.objects.create(
api_interfaces_case_name=str(api_case.api_interfaces_case_name) + "-Copy",
api_documentation=api_case.api_documentation,
api_management_id=api_case.api_management_id,
api_environment_id=api_case.api_environment_id,
api_method=api_case.api_method,
api_url=api_case.api_url,
api_parameter_types=api_case.api_parameter_types,
api_headers=api_case.api_headers,
api_parameter_body=api_case.api_parameter_body,
api_assert_type=api_case.api_assert_type,
dataBase_id=api_case.dataBase_id,
database_sql=api_case.database_sql,
api_assert_text=api_case.api_assert_text
)
api_interfaces_parameter_data = ApiInterfacesParameterData.objects.filter(
api_test_case_id=params['case_id'])
for api_interfaces_parameter in api_interfaces_parameter_data:
ApiInterfacesParameterData.objects.create(
api_test_case_id=copy_api_interfaces_case.id,
api_parameter_name=api_interfaces_parameter.api_parameter_name,
api_must_parameter=api_interfaces_parameter.api_must_parameter,
api_parameter_value=api_interfaces_parameter.api_parameter_value,
api_field_describe=api_interfaces_parameter.api_field_describe
)
return response_success({"message": "Copy成功!"})
# -*- coding: utf-8 -*-
# @Time : 2022/7/15 17:01
# @Author : wangyinghao
# @Site :
# @File : api_interfaces_case_view.py
# @Software: PyCharm
from datetime import datetime
from django.views.generic import View
import json
import re
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase, ApiInterfacesParameterData
from automated_main.form.api_interfaces_case import ApiInterfacesCaseForm
from automated_main.utils.api_utils import RegularMatch, InterfaceRequest, ExtractParameters
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.handle_db import HandleDB
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesParameterExtraction
from automated_main.utils.api_test_case_excel import HandleExcel
from django.http import FileResponse
import time
import random
import os
import logging
logger = logging.getLogger('django')
class ApiInterfacesCaseView(View):
def put(self, request, *args, **kwargs):
"""
创建接口测试用例
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiInterfacesCaseForm(data)
if form.is_valid():
api_interfaces_case = ApiInterfacesCase.objects.create(**form.cleaned_data)
api_test_case_id = api_interfaces_case.id
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
pass
elif api_parameter_extraction['api_key_variable'] != "":
if ApiInterfacesParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
api_test_case_id.delete()
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiInterfacesParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
for api_parameter in data['api_parameter']:
ApiInterfacesParameterData.objects.create(api_test_case_id=api_test_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
return response_success("创建API测试用例成功")
else:
raise MyException()
def get(self, request, api_interfaces_case_id, *args, **kwargs):
"""
获取单独接口测试用例
:param request:
:param args:
:param api_interfaces_case_id:
:param kwargs:
:return:
"""
api_test_case = ApiInterfacesCase.objects.filter(id=api_interfaces_case_id).first()
api_parameter_extractions = ApiInterfacesParameterExtraction.objects.filter(
api_test_case_id=api_interfaces_case_id)
api_parameter_extraction_list = []
api_parameter_data_list = []
api_parameter_data = ApiInterfacesParameterData.objects.filter(api_test_case_id=api_interfaces_case_id)
if api_parameter_data.count() > 0:
for api_parameter in api_parameter_data:
api_parameter_dict = {
"api_must_parameter": api_parameter.api_must_parameter,
"api_parameter_name": api_parameter.api_parameter_name,
"api_parameter_value": api_parameter.api_parameter_value,
"api_field_describe": api_parameter.api_field_describe
}
api_parameter_data_list.append(api_parameter_dict)
if api_parameter_extractions.count() > 0:
for api_parameter_extraction in api_parameter_extractions:
api_parameter_extraction_dict = {
"api_variable_results": api_parameter_extraction.api_variable_results,
"api_value_variable": api_parameter_extraction.api_value_variable,
"api_key_variable": api_parameter_extraction.api_key_variable
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
else:
api_parameter_extraction_dict = {
"api_variable_results": "",
"api_value_variable": "",
"api_key_variable": ""
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
if api_test_case is None:
return response_success()
else:
api_test_case_dict = model_to_dict(api_test_case)
api_test_case_dict['api_parameter_extraction'] = api_parameter_extraction_list
api_test_case_dict['api_parameter'] = api_parameter_data_list
return response_success(api_test_case_dict)
def post(self, request, api_interfaces_case_id, *args, **kwargs):
"""
编辑API测试用例
:param request:
:param args:
:param api_interfaces_case_id:
:param kwargs:
:return:
"""
api_test_case = ApiInterfacesCase.objects.filter(id=api_interfaces_case_id).first()
if api_test_case is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiInterfacesCaseForm(data)
if form.is_valid():
if ApiInterfacesParameterExtraction.objects.filter(api_test_case_id=api_interfaces_case_id).count() > 0:
ApiInterfacesParameterExtraction.objects.filter(api_test_case_id=api_interfaces_case_id).delete()
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
pass
elif ApiInterfacesParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiInterfacesParameterExtraction.objects.create(api_test_case_id=api_interfaces_case_id,
api_variable_results=api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
else:
logger.info("自定义变量表中 无 该 case_id")
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
logger.info("api_key_variable是空")
pass
elif api_parameter_extraction['api_key_variable'] != "":
if ApiInterfacesParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiInterfacesParameterExtraction.objects.create(api_test_case_id=api_interfaces_case_id,
api_variable_results=
api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
if ApiInterfacesParameterData.objects.filter(api_test_case_id=api_interfaces_case_id).count() > 0:
ApiInterfacesParameterData.objects.filter(api_test_case_id=api_interfaces_case_id).delete()
for api_parameter in data['api_parameter']:
ApiInterfacesParameterData.objects.create(api_test_case_id=api_interfaces_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
else:
for api_parameter in data['api_parameter']:
ApiInterfacesParameterData.objects.create(api_test_case_id=api_interfaces_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
ApiInterfacesCase.objects.filter(id=api_interfaces_case_id).update(update_time=datetime.now())
ApiInterfacesCase.objects.filter(id=api_interfaces_case_id).update(**form.cleaned_data)
return response_success("修改API测试用例成功")
else:
raise MyException()
def delete(self, request, api_interfaces_case_id, *args, **kwargs):
"""
删除接口测试用例
:param request:
:param api_interfaces_case_id:
:param args:
:param kwargs:
:return:
"""
ApiInterfacesCase.objects.get(id=api_interfaces_case_id).delete()
return response_success("删除API测试用例成功")
class ApiInterfacesCaseDeBugView(View):
def post(self, request, *args, **kwargs):
"""
API测试用例调试
:param request:
:param args:
:param kwargs:
:return:
"""
data_payload = ''
api_result = ''
body = request.body
if not body:
return response_success()
data = json.loads(body)
# noinspection PyBroadException
try:
api_environment = APIEnvironment.objects.get(id=data['api_environment_id'])
except Exception:
return response_failed("30000", "请选择域名")
# 请求地址
api_url = api_environment.api_title + data['api_url']
api_url = RegularMatch(api_url, data['api_environment_id'], regular="new")
logger.info("************************")
logger.info("请求地址: %s", api_url)
logger.info("************************")
if api_url[0] == "该变量数据库未找到":
return response_failed("4000", str(api_url[0] + api_url[1]))
api_headers = RegularMatch(data['api_headers'], data['api_environment_id'], regular="new")
if api_headers[0] == "该变量数据库未找到":
return response_failed("4000", str(api_headers[0] + api_headers[1]))
json_header = api_headers.replace("\'", "\"")
if data['api_headers'] == '':
header = data['api_headers']
else:
try:
header = json.loads(json_header)
except json.decoder.JSONDecodeError:
return response_failed("30000", "header类型错误" + json_header)
logger.info(json_header)
# Params参数
api_parameter = {}
for api_parameters in data['api_parameter']:
if api_parameters['api_must_parameter'] == "true":
api_parameter.update({api_parameters['api_parameter_name']: api_parameters['api_parameter_value']})
else:
pass
api_parameter_data = RegularMatch(str(api_parameter), data['api_environment_id'], regular="new")
if api_parameter_data[0] == "该变量数据库未找到":
return response_failed("4000", str(api_parameter_data[0] + api_parameter_data[1]))
data_parameter = api_parameter_data.replace("\'", "\"")
if data_parameter == '':
data_payload = api_parameter_data
logger.info(data_payload)
else:
try:
data_payload = json.loads(data_parameter)
logger.info(data_payload)
except json.decoder.JSONDecodeError:
return response_failed("30000", "参数类型错误" + data_payload)
api_parameter_body = RegularMatch(data['api_parameter_body'], data['api_environment_id'], regular="new")
if api_parameter_body[0] == "该变量数据库未找到":
return response_failed("4000", str(api_parameter_body[0] + api_parameter_body[1]))
json_par = api_parameter_body.replace("\'", "\"")
if api_parameter_body == '':
payload = api_parameter_body
logger.info(payload)
else:
try:
payload = json.loads(json_par)
logger.info(payload)
except json.decoder.JSONDecodeError:
return response_failed("30000", "参数类型错误" + json_par)
r = InterfaceRequest(str(data['api_method']), str(data['api_parameter_types']), api_url, header, payload,
data_payload)
logger.info("测试用例名称: %s", data['api_interfaces_case_name'])
logger.info("请求地址: %s", r.url)
logger.info("请求json数据: %s", payload)
logger.info("请求parameter数据: %s", data_payload)
logger.info("请求头: %s", r.headers)
logger.info("请求响应: %s", r.text)
if r == "请求超时":
return response_failed("30000", "接口超时", {'api_url': api_url,
"api_method": int(data['api_method']),
'api_header': header,
'api_body': payload,
'api_code': "请求超时",
'api_assert': "请求超时,断言失败",
'response_message': {"results": "请求超时"},
'response_time': 0,
'api_parameter_data': api_parameter})
# r.encoding = r.apparent_encoding
try:
response_message = r.json()
except json.decoder.JSONDecodeError:
return response_failed("30000", "接口返回结果类型错误非JSON格式", {'api_url': api_url,
"api_method": int(data['api_method']),
'api_header': header,
'api_body': payload,
'api_code': str(r.status_code),
'response_message': r.text,
'response_time': str(r.elapsed.total_seconds()),
'api_parameter_data': api_parameter})
# 断言
if data['api_assert_type'] == '':
result = "断言内容为空"
elif data['api_assert_type'] == 1:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"), r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(data['api_assert_text'].split())
assert r_text_data in r_text_test
result = "断言成功"
except Exception as e:
result = "断言失败: 响应内容中未包含 断言内容,断言内容: %s ,响应内容:%s" % (
data['api_assert_text'], r_text_test)
logger.error(result + str(e))
pass
elif data['api_assert_type'] == 2:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"), r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(data['api_assert_text'].split())
assert r_text_data == r_text_test
result = "断言成功"
except Exception as e:
result = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (
data['api_assert_text'], r_text_test)
logger.error(result + str(e))
pass
elif data['api_assert_type'] == 3:
database = APIDatabase.objects.get(id=data['dataBase'])
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
sql = data['database_sql']
count = db.get_count(sql)
db.close()
if str(count) == str(data['api_assert_text']):
result = '断言成功'
else:
result = '断言失败,查询的数据是: %s' % str(count)
elif data['api_assert_type'] == 4:
try:
assert data['api_assert_text'] == str(r.status_code)
result = "断言成功"
except Exception as e:
result = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (data['api_assert_text'], str(r.status_code))
logger.error(result + str(e))
pass
api_variable_results = []
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_value_variable'] == "":
api_parameter_extraction_dict = {
"api_variable_results": "无参数提取",
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
}
api_variable_results.append(api_parameter_extraction_dict)
elif ApiInterfacesParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() >= 0:
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
logger.info('json转换失败(变量):' + str(e))
pass
v_text = api_parameter_extraction['api_value_variable'].split(".")
logger.info('这是提取' + str(v_text))
try:
api_result = ExtractParameters(v_text, api_result)
api_parameter_extraction_dict = {
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
"api_variable_results": str(api_result)
}
api_variable_results.append(api_parameter_extraction_dict)
except Exception as e:
logger.info('参数提取异常' + str(e))
api_parameter_extraction_dict = {
"api_variable_results": api_parameter_extraction['api_key_variable'],
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
}
api_variable_results.append(api_parameter_extraction_dict)
logger.info(api_variable_results)
return response_success({'api_url': api_url,
'api_header': header,
'api_body': payload,
'api_code': str(r.status_code),
'api_assert': str(result),
"api_method": int(data['api_method']),
'response_message': response_message,
'response_time': str(r.elapsed.total_seconds()),
'api_parameter_extraction': api_variable_results,
'api_parameter_data': api_parameter})
\ No newline at end of file
# -*- coding: utf-8 -*-
# @Time : 2022/5/24 21:30
# @Author : wangyinghao
# @Site :
# @File : api_management_detail_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.form.api_management import ApiManagementForm
from automated_main.models.api_automation.api_management import ApiManagement
from datetime import datetime
class ApiManagementView(View):
def get(self, request, api_management_id, *args, **kwargs):
"""
代表获取单个服务
:param request:
:param api_management_id:
:param args:
:param kwargs:
:return:
"""
try:
api_management = ApiManagement.objects.get(id=api_management_id)
except ApiManagement.DoesNotExist:
return response_failed()
else:
return response_success(model_to_dict(api_management))
def post(self, request, api_management_id, *args, **kwargs):
"""
更新单个服务
:param request:
:param api_management_id:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
form = ApiManagementForm(params)
result = form.is_valid()
if result:
api_management_data = ApiManagement.objects.get(id=api_management_id)
api_management_data.name = params['name']
api_management_data.description = params['description']
api_management_data.parent = params['parent']
api_management_data.update_time = datetime.now()
api_management_data.save()
else:
print(form.errors.as_json())
raise MyException()
return response_success()
def delete(self, request, api_management_id, *args, **kwargs):
ApiManagement.objects.filter(id=api_management_id).delete()
ApiManagement.objects.filter(parent=api_management_id).delete()
return response_success()
# -*- coding: utf-8 -*-
# @Time : 2022/5/24 21:30
# @Author : wangyinghao
# @Site :
# @File : api_management_list_view.py
# @Software: PyCharm
import requests
from django.views.generic import View
import json
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_management import ApiManagement, IS_ROOT
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase
from datetime import datetime
from automated_main.utils.api_yapi_util import ApiYapiServer
from automated_main.form.api_management import ApiManagementForm
class ApiManagementListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取服务列表
:param request:
:param args:
:param kwargs:
:return:
"""
api_management_data = ApiManagement.objects.filter(parent=0)
api_management_list = []
for api_management in api_management_data:
api_management_dict = {
"id": api_management.id,
"name": api_management.name,
"parent": api_management.parent,
"description": api_management.description,
"icon": "el-icon-folder-opened"
}
api_management_list.append(api_management_dict)
return response_success(api_management_list)
def put(self, request, *args, **kwargs):
"""
创建服务
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
form = ApiManagementForm(params)
result = form.is_valid()
if result:
api_management = ApiManagement.objects.create(**form.cleaned_data)
if api_management:
return response_success()
else:
raise MyException("创建失败")
else:
return response_failed()
def post(self, request, *args, **kwargs):
"""
获取服务下一级别的服务
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
api_management_list = []
if params == {}:
pass
else:
api_management_data = ApiManagement.objects.filter(parent=params['parent'])
if params['isLeaf'] == "false":
for api_management in api_management_data:
api_management_dict = {
"id": api_management.id,
"name": api_management.name,
"parent": api_management.parent,
"description": api_management.description,
"icon": "el-icon-folder-opened"
}
api_management_list.append(api_management_dict)
else:
for api_management in api_management_data:
api_management_dict = {
"id": api_management.id,
"name": api_management.name,
"parent": api_management.parent,
"description": api_management.description,
"isParent": True,
"icon": "el-icon-lx-text"
}
api_management_list.append(api_management_dict)
return response_success(api_management_list)
class ApiManagementSearchView(View):
def post(self, request, *args, **kwargs):
"""
搜索服务
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
print(params)
api_management_list = []
management_data = ApiManagement.objects.filter(name__icontains=params['management_name'])
for management in management_data:
print(management.name)
# if management.parent != 0:
# api_data = ApiManagement.objects.filter(id=management.parent)
# for api in api_data:
# if api.parent != 0:
# api2_data = ApiManagement.objects.filter(id=api.parent)
# for api3 in api2_data:
# if api3.parent != 0:
# print("我没有父节点")
# else:
# print("**********3")
# print(api3.name)
#
# else:
# print("**********2")
# print(api.name)
# else:
# print("******1")
# print(management.name)
return response_success(api_management_list)
class ApiManagementJudgeView(View):
def post(self, request, *args, **kwargs):
"""
判断 父节点 是否可创建用例(只有用例节点才可创建用例)
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
try:
api_management_data_a = ApiManagement.objects.get(id=params['service_id'])
except ApiManagement.DoesNotExist:
return response_failed(message="该节点无权限创建用例,请先创建项目节点")
if api_management_data_a.parent == 0:
return response_failed(message="该节点无权限创建用例,请先创建服务节点")
else:
api_management_data_b = ApiManagement.objects.get(id=api_management_data_a.parent)
if api_management_data_b.parent == 0:
return response_failed(message="该节点无权限创建用例,请先创建接口节点")
else:
return response_success()
class ApiManagementStructureDataEditView(View):
def get(self, request, *args, **kwargs):
"""
tree树结构更改 为二级目录,测试用例变更-8.23修改数据
:param request:
:param args:
:param kwargs:
:return:
"""
api_management_data = ApiManagement.objects.filter(parent=0)
api_management = []
try:
for api_management_tree in api_management_data:
# 一级目录
api_management_tree_data2 = ApiManagement.objects.filter(parent=api_management_tree.id)
for api_management_tree_2 in api_management_tree_data2:
api_management_tree_data3 = ApiManagement.objects.filter(parent=api_management_tree_2.id)
# 二级目录
for api_management_tree_3 in api_management_tree_data3:
api_management_tree_data4 = ApiManagement.objects.filter(parent=api_management_tree_3.id)
# 三级目录
for api_management_tree_4 in api_management_tree_data4:
# 四级目录
apimanagement_updata = ApiManagement.objects.get(id=api_management_tree_4.id)
apimanagement_updata.parent = api_management_tree_2.id
apimanagement_updata.save()
# apimanagement_updata.objects.update(parent=api_management_tree_2.id)
except Exception as e:
print("************")
pass
return response_success(api_management)
class YaPiInterfaceBasicInformationView(View):
def post(self, request, *args, **kwargs):
"""
获取YAPI接口基本信息
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
api_management_data = ApiManagement.objects.filter(id=params['serviceId'])
api = []
for api_management in api_management_data:
if api_management.yapi_id is None:
api_dict = {
"yapi_api": 0
}
api.append(api_dict)
else:
api_yapi_server_data = ApiYapiServer.api_yapi_server_data(api_management.yapi_id)
api_dict = {
"yapi_api": 1,
"api_interfaces_case_name": "",
"api_environment": "",
"api_documentation": api_yapi_server_data['api_documentation'],
"api_method": api_yapi_server_data['api_method'],
"api_url": api_yapi_server_data['api_url'],
"api_parameter_types": api_yapi_server_data['api_parameter_types'],
"api_parameter": api_yapi_server_data['api_parameter'],
"api_headers": api_yapi_server_data['api_headers'],
"api_parameter_body": api_yapi_server_data['api_parameter_body'],
"api_assert_type": 1
}
api.append(api_dict)
return response_success(api)
class ApiYaPiInterfaceView(View):
def put(self, request, *args, **kwargs):
"""
创建接口-tree树-对接YaPi创建接口
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
server_data = ApiManagement.objects.filter(name=params['server_name'])
if server_data.count() == 1:
for api_server_data in server_data:
ApiManagement.objects.create(name=params['api_name'], parent=api_server_data.id,
yapi_id=params['yapi_id'])
elif server_data.count() > 1:
return response_failed(20000, message="服务名称重复,请查看数据")
else:
return response_failed(20000, message="请先创建服务")
return response_success()
def post(self, request, *args, **kwargs):
"""
YAPI接口更新接口时间
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
server_data = ApiManagement.objects.filter(yapi_id=params['yap_id'])
if server_data.count() == 1:
for api_server_data in server_data:
api_server_data.update_time = datetime.now()
api_server_data.save()
return response_success()
elif server_data.count() > 1:
return response_failed(20000, message="接口名id重复,请查看数据")
else:
return response_failed(20000, message="平台中暂无该接口id")
# -*- coding: utf-8 -*-
# @Time : 2021/3/3 11:01
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/3/3 11:02
# @Author : wangyinghao
# @FileName: api_module_list_view.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.views.generic import View
# from automated_main.utils.http_format import response_success
# from automated_main.models.api_automation.api_module import APIModule
# import arrow
#
#
# class ApiModuleListView(View):
#
# def get(self, request, *args, **kwargs):
# """
# 代表获取所有Api模块列表
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
#
# api_module = APIModule.objects.all().order_by('-id')
# api_module_list = []
#
# for api_modules in api_module:
# api_module_dict = {
# "id": api_modules.id,
# "api_module_name": api_modules.ui_page_name,
# "api_module_describe": api_modules.ui_page_describe,
# "updata_time": arrow.get(str(api_modules.updata_time)).format('YYYY-MM-DD HH:mm:ss'),
# "create_time": arrow.get(str(api_modules.create_time)).format('YYYY-MM-DD HH:mm:ss'),
# "api_project_name": api_modules.ui_project.ui_project_name
# }
# api_module_list.append(api_module_dict)
#
# return response_success(api_module_list)
# -*- coding: utf-8 -*-
# @Time : 2021/3/3 11:02
# @Author : wangyinghao
# @FileName: api_module_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_module import APIModule
from django.core.paginator import Paginator
import arrow
from automated_main.form.api_module import ApiModuleForm
class ApiModuleView(View):
def get(self, request, api_module_id, *args, **kwargs):
"""
代表获取单个API模块
:param request:
:param api_module_id: API模块ID
:param args:
:param kwargs:
:return:
"""
api_module = APIModule.objects.filter(id=api_module_id).first()
if api_module is None:
return response_success()
else:
return response_success(model_to_dict(api_module))
def post(self, request, api_module_id, *args, **kwargs):
"""
代表更改页面
:param request:
:param api_module_id: API模块ID
:param args:
:param kwargs:
:return:
"""
api_module = APIModule.objects.filter(id=api_module_id).first()
if api_module is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiModuleForm(data)
if form.is_valid():
APIModule.objects.filter(id=api_module_id).update(**form.cleaned_data)
return response_success("编辑API模块成功")
else:
raise MyException()
def delete(self, request, api_module_id, *args, **kwargs):
"""
代表删除单独模块
:param request:
:param api_module_id: API模块ID
:param args:
:param kwargs:
:return:
"""
APIModule.objects.filter(id=api_module_id).delete()
return response_success("删除模块成功")
def put(self, request, *args, **kwargs):
"""
代表创建模块
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiModuleForm(data)
if form.is_valid():
APIModule.objects.create(**form.cleaned_data)
return response_success("创建成功")
else:
raise MyException(message="创建失败")
class ApiProjectModuleView(View):
def get(self, request, api_project_id, size_page, page, *args, **kwargs):
"""
获取 单个API项目中包含得所有模块
:param page: 页数
:param size_page: 展示条数
:param request:
:param api_project_id: api项目id
:param args:
:param kwargs:
:return:
"""
api_module = APIModule.objects.filter(api_project_id=api_project_id)
api_module_list = []
for api_modules in api_module:
api_module_dict = {
"id": api_modules.id,
"api_project_name": api_modules.api_project.api_project_name,
"api_module_name": api_modules.api_module_name,
"api_module_describe": api_modules.api_module_describe,
"updata_time": arrow.get(str(api_modules.updata_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_modules.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_module_list.append(api_module_dict)
p = Paginator(api_module_list, size_page)
if int(page) > int(p.num_pages):
page1 = p.page(p.num_pages)
current_page = page1.object_list
else:
page1 = p.page(page)
current_page = page1.object_list
total_module = len(api_module_list)
if api_module is None:
return response_success()
else:
return response_success({'status': 200, 'data': current_page, 'total_module': total_module})
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:40
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:41
# @Author : wangyinghao
# @FileName: api_project_list_view.py
# @Software: PyCharm
from django.views.generic import View
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_project import APIProject
import arrow
class ApiProjectListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取所有API测试项目列表
:param request:
:param args:
:param kwargs:
:return:
"""
api_projects = APIProject.objects.all().order_by('-id')
api_project_list = []
for api_project in api_projects:
api_project_dict = {
"id": api_project.id,
"api_project_name": api_project.api_project_name,
"describe": api_project.describe,
"updata_time": arrow.get(str(api_project.updata_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_project.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_project_list.append(api_project_dict)
return response_success(api_project_list)
# -*- coding: utf-8 -*-
# @Time : 2021/3/2 18:41
# @Author : wangyinghao
# @FileName: api_project_view.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.views.generic import View
# import json
# from django.forms import model_to_dict
# from automated_main.utils.http_format import response_success
# from automated_main.exception.my_exception import MyException
# from automated_main.models.api_automation.api_project import APIProject
# from automated_main.form.api_project import ApiProjectForm
# class ApiProjectView(View):
#
# def get(self, request, api_project_id, *args, **kwargs):
# """
# 代表获取单个API项目
# :param request:
# :param api_project_id: API项目ID
# :param args:
# :param kwargs:
# :return:
# """
#
# api_project = APIProject.objects.filter(id=api_project_id).first()
# if api_project is None:
# return response_success()
# else:
# return response_success(model_to_dict(api_project))
#
# def post(self, request, api_project_id, *args, **kwargs):
# """
# 代表更改API项目
# :param request:
# :param api_project_id:API项目ID
# :param args:
# :param kwargs:
# :return:
# """
#
# api_project = APIProject.objects.filter(id=api_project_id).first()
# if api_project is None:
# return response_success()
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
#
# form = ApiProjectForm(data)
#
# if form.is_valid():
#
# APIProject.objects.filter(id=api_project_id).update(**form.cleaned_data)
# return response_success("编辑UI项目成功")
# else:
# raise MyException()
#
# def delete(self, request, api_project_id, *args, **kwargs):
# """
# 代表删除单独API项目
# :param request:
# :param api_project_id: API项目ID
# :param args:
# :param kwargs:
# :return:
# """
#
# APIProject.objects.filter(id=api_project_id).delete()
# return response_success()
#
# def put(self, request, *args, **kwargs):
# """
# 代表创建API项目
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
#
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
#
# form = ApiProjectForm(data)
#
# if form.is_valid():
# APIProject.objects.create(**form.cleaned_data)
# return response_success()
# else:
# raise MyException()
# -*- coding: utf-8 -*-
# @Time : 2022/7/19 11:48
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2022/7/19 11:49
# @Author : wangyinghao
# @Site :
# @File : api_scenarios_case_list_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCaseAssociated, ApiScenariosCase
class ApiScenariosCaseListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取所有API接口用例tree-一级目录
:param request:
:param args:
:param kwargs:
:return:
"""
api_management_data = ApiManagement.objects.filter(parent=0).order_by('-id')
api_management_list = []
for api_management in api_management_data:
api_management_dict = {
"id": api_management.id,
"name": api_management.name,
"parent": api_management.parent,
"description": api_management.description,
"icon": "el-icon-folder-opened"
}
api_management_list.append(api_management_dict)
return response_success(api_management_list)
def post(self, request, *args, **kwargs):
"""
代表获取所有API接口用例tree-用例
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
api_interfaces_case_list = []
if params == {}:
pass
else:
api_interfaces_case_data = ApiInterfacesCase.objects.filter(api_management_id=params['parent'])
for api_interfaces_case in api_interfaces_case_data:
api_interfaces_case_dict = {
"case_id": api_interfaces_case.id,
"id": api_interfaces_case.id,
"name": api_interfaces_case.api_interfaces_case_name,
"children": "",
"isParent": True,
"icon": "el-icon-tickets"
}
api_interfaces_case_list.append(api_interfaces_case_dict)
return response_success(api_interfaces_case_list)
class InterfacesProjectListView(View):
def get(self, request, *args, **kwargs):
"""
代表获取所有API接口项目列表
:param request:
:param args:
:param kwargs:
:return:
"""
api_management = ApiManagement.objects.filter(parent=0)
api_management_data_list = []
for api_management_data in api_management:
api_management_dict = {
"api_management_id": api_management_data.id,
"api_management_name": api_management_data.name,
}
api_management_data_list.append(api_management_dict)
return response_success(api_management_data_list)
class ServiceModuleInterfacesCaseRelationshipView(View):
def post(self, request, *args, **kwargs):
"""
代表获取 服务、模块、接口、用例关系
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
api_case = ApiInterfacesCase.objects.get(id=params['case_id'])
interfaces_name = ApiManagement.objects.get(id=api_case.api_management_id)
api_module_name = ApiManagement.objects.get(id=interfaces_name.parent)
api_service_name = ApiManagement.objects.get(id=api_module_name.parent)
api_management_dict = {
"interfaces_name": interfaces_name.name,
"api_module_name": api_module_name.name,
"api_service_name": api_service_name.name,
}
return response_success(api_management_dict)
class ApiScenariosCaseCopyView(View):
def post(self, request, *args, **kwargs):
"""
Copy场景用例
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
params = json.loads(body)
api_scenarios_case_data = ApiScenariosCase.objects.filter(id=params['sid_id'])
for api_scenarios_case in api_scenarios_case_data:
api_scenarios_case_copy = ApiScenariosCase.objects.create(
api_scenarios_case_name=str(api_scenarios_case.api_scenarios_case_name) + "-Copy",
api_scenarios_case_describe=api_scenarios_case.api_scenarios_case_describe,
api_management_id=api_scenarios_case.api_management_id
)
api_scenarios_case_associated_copy = ApiScenariosCaseAssociated.objects.filter(sid_id=params['sid_id'])
for api_scenarios_case_associated in api_scenarios_case_associated_copy:
ApiScenariosCaseAssociated.objects.create(sid_id=api_scenarios_case_copy.id,
interfaces_case_id=api_scenarios_case_associated.interfaces_case_id,
case_steps=api_scenarios_case_associated.case_steps)
return response_success({"message": "Copy成功!"})
# -*- coding: utf-8 -*-
# @Time : 2022/7/20 10:30
# @Author : wangyinghao
# @Site :
# @File : api_scenarios_case_view.py
# @Software: PyCharm
from django.views.generic import View
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.utils.handle_db import HandleDB
from automated_main.utils.api_utils import RegularMatch, InterfaceRequest, ExtractParameters
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCaseAssociated, ApiScenariosCase
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase, \
ApiInterfacesParameterExtraction, ApiInterfacesParameterData
from automated_main.form.api_scenarios_case import ApiScenariosCaseForm
from automated_main.models.api_automation.api_management import ApiManagement
from datetime import datetime
import arrow
import ast
import json
import re
import logging
logger = logging.getLogger('django')
class ApiScenariosCaseView(View):
def get(self, request, api_management_id, *args, **kwargs):
"""
获取场景用例列表
:param request:
:param args:
:param api_management_id:
:param kwargs:
:return:
"""
api_scenarios_case_data = ApiScenariosCase.objects.filter(api_management_id=api_management_id)
api_scenarios_case_data_list = []
for api_scenarios_case in api_scenarios_case_data:
api_scenarios_case_data_dict = {
"id": api_scenarios_case.id,
"api_scenarios_case_name": api_scenarios_case.api_scenarios_case_name,
"api_scenarios_case_describe": api_scenarios_case.api_scenarios_case_describe,
"update_time": arrow.get(str(api_scenarios_case.update_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_scenarios_case.create_time)).format('YYYY-MM-DD HH:mm:ss')
}
api_scenarios_case_data_list.append(api_scenarios_case_data_dict)
return response_success(api_scenarios_case_data_list)
def delete(self, request, scenarios_case_id, *args, **kwargs):
"""
删除场景测试用例
:param request:
:param args:
:param scenarios_case_id:
:param kwargs:
:return:
"""
ApiScenariosCase.objects.get(id=scenarios_case_id).delete()
return response_success("删除API测试用例成功")
def put(self, request, *args, **kwargs):
"""
创建API场景测试
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiScenariosCaseForm(data)
if form.is_valid():
api_scenarios_case = ApiScenariosCase.objects.create(**form.cleaned_data)
api_scenarios_case_id = api_scenarios_case.id
for i in data["api_scenarios_case_data"]:
api_interfaces_case_id = (i['api_interfaces_case_id'])
case_steps = (i['case_steps'])
ApiScenariosCaseAssociated.objects.create(sid_id=api_scenarios_case_id,
interfaces_case_id=api_interfaces_case_id,
case_steps=case_steps
)
return response_success("创建API业务测试用例成功")
else:
raise MyException()
def post(self, request, scenarios_case_id, *args, **kwargs):
"""
编辑API场景测试
:param request:
:param args:
:param scenarios_case_id:
:param kwargs:
:return:
"""
api_scenarios_case = ApiScenariosCase.objects.get(id=scenarios_case_id)
if api_scenarios_case is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiScenariosCaseForm(data)
api_scenarios_case.api_scenarios_case_name = data['api_scenarios_case_name']
api_scenarios_case.api_scenarios_case_describe = data['api_scenarios_case_describe']
api_scenarios_case.api_management_id = data['api_management_id']
api_scenarios_case.update_time = datetime.now()
api_scenarios_case.save()
ApiScenariosCaseAssociated.objects.filter(sid_id=api_scenarios_case.id).delete()
if form.is_valid():
for i in data["api_scenarios_case_data"]:
api_interfaces_case_id = (i['api_interfaces_case_id'])
case_steps = (i['case_steps'])
ApiScenariosCaseAssociated.objects.create(sid_id=api_scenarios_case.id,
interfaces_case_id=api_interfaces_case_id,
case_steps=case_steps)
return response_success("编辑API场景测试用例成功")
else:
raise MyException()
class ApiScenariosCaseGetView(View):
def get(self, request, scenarios_case_id, *args, **kwargs):
"""
获取场景用例-组合
:param request:
:param args:
:param scenarios_case_id:
:param kwargs:
:return:
"""
api_scenarios_case_associated_data = ApiScenariosCaseAssociated.objects.filter(sid_id=scenarios_case_id)
api_scenarios_case_associated_data_list = []
for api_scenarios_case_associated in api_scenarios_case_associated_data:
api_case = ApiInterfacesCase.objects.get(id=api_scenarios_case_associated.interfaces_case_id)
interfaces_name = ApiManagement.objects.get(id=api_case.api_management_id)
api_module_name = ApiManagement.objects.get(id=interfaces_name.parent)
api_service_name = ApiManagement.objects.get(id=api_module_name.parent)
api_scenarios_case_associated_dict = {
"case_steps": api_scenarios_case_associated.case_steps,
"api_scenarios_case_name": api_scenarios_case_associated.interfaces_case.api_interfaces_case_name,
"api_interfaces_case_id": api_scenarios_case_associated.interfaces_case.id,
"interfaces_name": interfaces_name.name,
"api_module_name": api_module_name.name,
"api_service_name": api_service_name.name,
}
api_scenarios_case_associated_data_list.append(api_scenarios_case_associated_dict)
return response_success(api_scenarios_case_associated_data_list)
class ApiScenariosCaseDebugView(View):
def post(self, request, *args, **kwargs):
"""
API场景测试DEBUG
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
for case in data['api_scenarios_case_data']:
interfaces_case = ApiInterfacesCase.objects.get(id=case['api_interfaces_case_id'])
api_environment = APIEnvironment.objects.get(id=data['environment'])
# 请求地址
api_url = api_environment.api_title + interfaces_case.api_url
api_url = RegularMatch(api_url, data['environment'], regular="new")
if api_url[0] == "该变量数据库未找到":
return response_failed("4000", str(api_url[0] + api_url[1]))
api_headers = RegularMatch(interfaces_case.api_headers, data['environment'], regular="new")
if api_headers[0] == "该变量数据库未找到":
return response_failed("4000", str(api_headers[0] + api_headers[1]))
json_header = api_headers.replace("\'", "\"")
if interfaces_case.api_headers == '':
header = interfaces_case.api_headers
else:
try:
header = json.loads(json_header)
except json.decoder.JSONDecodeError:
return response_failed('30000', "header类型错误,用例名称: " + str(interfaces_case.api_interfaces_case_name))
logger.info(json_header)
api_parameter_body = RegularMatch(interfaces_case.api_parameter_body, data['environment'], regular="new")
if api_parameter_body[0] == "该变量数据库未找到":
return response_failed('40000', "该变量数据库未找到,用例名称: " + str(
interfaces_case.api_interfaces_case_name) + "\n" + "变量值:" +
str(api_parameter_body[0] + api_parameter_body[1]))
json_par = api_parameter_body.replace("\'", "\"")
if api_parameter_body == '':
payload = api_parameter_body
logger.info(payload)
else:
try:
payload = json.loads(json_par)
logger.info(payload)
except json.decoder.JSONDecodeError:
return response_failed('30000', "参数类型错误,用例名称: " + str(interfaces_case.api_interfaces_case_name))
parameter_data = ApiInterfacesParameterData.objects.filter(api_test_case_id=case['api_interfaces_case_id'])
api_parameter_dict = {}
for api_parameters in parameter_data:
if api_parameters.api_must_parameter == "true":
api_parameter_dict.update(
{api_parameters.api_parameter_name: api_parameters.api_parameter_value})
else:
pass
if api_parameter_dict == {}:
api_parameter_data = {}
else:
api_parameter_data = RegularMatch(str(api_parameter_dict), data['environment'], regular="new")
if api_parameter_data == {}:
data_payload = api_parameter_data
logger.info(data_payload)
else:
try:
data_payload = ast.literal_eval(api_parameter_data)
except json.decoder.JSONDecodeError:
return response_failed("30000", "Parameter参数类型错误" + api_parameter_data)
r = InterfaceRequest(str(interfaces_case.api_method), str(interfaces_case.api_parameter_types),
api_url, header, payload, data_payload)
logger.info("请求地址: %s", r.url)
logger.info("请求json数据: %s", payload)
logger.info("请求parameter数据: %s", data_payload)
logger.info("请求头: %s", r.headers)
logger.info("请求响应: %s", r.text)
if r == "请求超时":
return response_failed('30000', "接口请求超时:" + str(interfaces_case.api_interfaces_case_name))
try:
response_message = r.json()
except json.decoder.JSONDecodeError:
return response_failed('30000', "接口返回结果类型错误非JSON格式:" + str(
interfaces_case.api_interfaces_case_name) + "\n" + str(r.text))
# 断言
if interfaces_case.api_assert_type == '':
result = "断言内容为空"
logger.error(result)
elif interfaces_case.api_assert_type == 1:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(interfaces_case.api_assert_text.split())
assert r_text_data in r_text_test
except Exception as e:
result = "断言失败: 响应内容中未包含 断言内容,断言内容: %s ,响应内容:%s" % (
interfaces_case.api_assert_text, r_text)
logger.error(result + str(e))
return response_failed('30000',
"断言失败,用例名称: " + str(interfaces_case.api_interfaces_case_name) + "\n" +
"断言结果:" + result)
elif interfaces_case.api_assert_type == 2:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(interfaces_case.api_assert_text.split())
assert r_text_data == r_text_test
except Exception as e:
result = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (
interfaces_case.api_assert_text, r_text)
logger.error(result, e)
return response_failed('30000',
"断言失败,用例名称: " + str(interfaces_case.api_interfaces_case_name) + "\n" +
"断言结果:" + result)
elif interfaces_case.api_assert_type == 3:
database = APIDatabase.objects.get(id=interfaces_case.dataBase_id)
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
sql = data['database_sql']
count = db.get_count(sql)
db.close()
if str(count) == str(interfaces_case.api_assert_text):
result = '断言成功'
logger.error(result)
else:
result = '断言失败,查询的数据是: %s' % str(count)
logger.error(result)
return response_failed('30000',
"断言失败,用例名称: " + str(interfaces_case.api_interfaces_case_name) + "\n" +
"断言结果:" + result)
elif interfaces_case.api_assert_type == 4:
try:
assert interfaces_case.api_assert_text == str(r.status_code)
result = "断言成功"
except Exception as e:
result = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (interfaces_case.api_assert_text, str(r.status_code))
logger.error(result + str(e))
return response_failed('30000',
"断言失败,用例名称: " + str(interfaces_case.api_interfaces_case_name) + "\n" +
"断言结果:" + result)
parameter_extraction = ApiInterfacesParameterExtraction.objects.filter(
api_test_case_id=case['api_interfaces_case_id'])
if parameter_extraction == "" or None:
pass
else:
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
logger.info('json转换失败(变量):' + str(e))
pass
for parameter_extractions in parameter_extraction:
v_text = parameter_extractions.api_value_variable.split(".")
try:
api_results = ExtractParameters(v_text, api_result)
api_parameter_extraction = ApiInterfacesParameterExtraction.objects.get(
api_key_variable=str(parameter_extractions.api_key_variable))
api_parameter_extraction.api_variable_results = str(api_results)
api_parameter_extraction.save()
except Exception as e:
logger.info('参数提取失败' + str(e))
return response_failed('30000', "参数提取失败,用例名称:" +
str(interfaces_case.api_interfaces_case_name) + '\n' + "异常信息:" + str(e))
return response_success("调试成功")
# -*- coding: utf-8 -*-
# @Time : 2021/3/29 17:30
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/3/29 18:58
# @Author : wangyinghao
# @FileName: api_test_case_list_view.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.views.generic import View
# from automated_main.utils.http_format import response_success
# from automated_main.models.api_automation.api_test_case import ApiTestCase
# import arrow
#
#
# class ApiTestCaseListView(View):
#
# def post(self, request, api_module_id, *args, **kwargs):
# """
# 获取测试用例列表
# :param request:
# :param api_module_id: API模块id
# :param args:
# :param kwargs:
# :return:
# """
# api_test_cases = ApiTestCase.objects.filter(api_module=api_module_id).order_by('-id')
# api_test_case_list = []
#
# for api_test_case in api_test_cases:
# api_test_case_dict = {
# "id": api_test_case.id,
# "api_module_name": api_test_case.api_module.api_module_name,
# "api_test_case_name": api_test_case.api_test_case_name,
# "api_test_case_url": api_test_case.api_url,
# "updata_time": arrow.get(str(api_test_case.update_time)).format('YYYY-MM-DD HH:mm:ss'),
# "create_time": arrow.get(str(api_test_case.create_time)).format('YYYY-MM-DD HH:mm:ss'),
# }
#
# api_test_case_list.append(api_test_case_dict)
# return response_success(api_test_case_list)
# -*- coding: utf-8 -*-
# @Time : 2021/4/1 10:50
# @Author : wangyinghao
# @FileName: api_test_case_view.py
# @Software: PyCharm
from django.views.generic import View
import json
import re
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_test_case import ApiTestCase, ApiParameterExtraction, ApiParameterData
from automated_main.form.api_test_case import ApiTestCaseForm
from automated_main.models.api_automation.api_environment import APIEnvironment
from automated_main.models.api_automation.api_project import APIProject
from automated_main.models.api_automation.api_module import APIModule
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.handle_db import HandleDB
from automated_main.utils.api_utils import RegularMatch, InterfaceRequest, ExtractParameters
from AutomatedTestPlatform import settings
from automated_main.utils.api_test_case_excel import HandleExcel
from django.http import FileResponse
import time
import random
import os
import logging
logger = logging.getLogger('django')
class ApiTestCaseView(View):
def delete(self, request, api_test_case_id, *args, **kwargs):
"""
代表删除API测试用例
:param request:
:param api_test_case_id:
:param args:
:param kwargs:
:return:
"""
ApiTestCase.objects.get(id=api_test_case_id).delete()
return response_success("删除API测试用例成功")
def put(self, request, *args, **kwargs):
"""
创建API测试用例
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiTestCaseForm(data)
if form.is_valid():
api_test_case = ApiTestCase.objects.create(**form.cleaned_data)
api_test_case_id = api_test_case.id
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
pass
elif api_parameter_extraction['api_key_variable'] != "":
if ApiParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
api_test_case.delete()
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
for api_parameter in data['api_parameter']:
ApiParameterData.objects.create(api_test_case_id=api_test_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
return response_success("创建API测试用例成功")
else:
raise MyException()
def post(self, request, api_test_case_id, *args, **kwargs):
"""
编辑API测试用例
:param request:
:param args:
:param api_test_case_id:
:param kwargs:
:return:
"""
api_test_case = ApiTestCase.objects.filter(id=api_test_case_id).first()
if api_test_case is None:
return response_success()
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiTestCaseForm(data)
if form.is_valid():
if ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).count() > 0:
ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).delete()
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
pass
elif ApiParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
else:
logger.info("自定义变量表中 无 该 case_id")
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_key_variable'] == "":
logger.info("api_key_variable是空")
pass
elif api_parameter_extraction['api_key_variable'] != "":
if ApiParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() > 0:
return response_failed("30000", "变量名称重复,请重新填写")
else:
ApiParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_parameter_extraction[
'api_variable_results'],
api_value_variable=api_parameter_extraction[
'api_value_variable'],
api_key_variable=api_parameter_extraction[
'api_key_variable'])
if ApiParameterData.objects.filter(api_test_case_id=api_test_case_id).count() > 0:
ApiParameterData.objects.filter(api_test_case_id=api_test_case_id).delete()
for api_parameter in data['api_parameter']:
ApiParameterData.objects.create(api_test_case_id=api_test_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
else:
for api_parameter in data['api_parameter']:
ApiParameterData.objects.create(api_test_case_id=api_test_case_id,
api_parameter_name=api_parameter['api_parameter_name'],
api_must_parameter=api_parameter['api_must_parameter'],
api_parameter_value=api_parameter['api_parameter_value'],
api_field_describe=api_parameter['api_field_describe'])
ApiTestCase.objects.filter(id=api_test_case_id).update(**form.cleaned_data)
return response_success("修改API测试用例成功")
else:
raise MyException()
def get(self, request, api_test_case_id, *args, **kwargs):
"""
获取单独API测试用例
:param request:
:param args:
:param api_test_case_id:
:param kwargs:
:return:
"""
api_test_case = ApiTestCase.objects.filter(id=api_test_case_id).first()
api_parameter_extractions = ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id)
api_parameter_extraction_list = []
api_parameter_data_list = []
api_parameter_data = ApiParameterData.objects.filter(api_test_case_id=api_test_case_id)
if api_parameter_data.count() > 0:
for api_parameter in api_parameter_data:
api_parameter_dict = {
"api_must_parameter": api_parameter.api_must_parameter,
"api_parameter_name": api_parameter.api_parameter_name,
"api_parameter_value": api_parameter.api_parameter_value,
"api_field_describe": api_parameter.api_field_describe
}
api_parameter_data_list.append(api_parameter_dict)
if api_parameter_extractions.count() > 0:
for api_parameter_extraction in api_parameter_extractions:
api_parameter_extraction_dict = {
"api_variable_results": api_parameter_extraction.api_variable_results,
"api_value_variable": api_parameter_extraction.api_value_variable,
"api_key_variable": api_parameter_extraction.api_key_variable
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
else:
api_parameter_extraction_dict = {
"api_variable_results": "",
"api_value_variable": "",
"api_key_variable": ""
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
if api_test_case is None:
return response_success()
else:
api_test_case_dict = model_to_dict(api_test_case)
api_test_case_dict['api_parameter_extraction'] = api_parameter_extraction_list
api_test_case_dict['api_parameter'] = api_parameter_data_list
return response_success(api_test_case_dict)
class ApiTestCaseDeBugView(View):
def post(self, request, *args, **kwargs):
"""
API测试用例调试
:param request:
:param args:
:param kwargs:
:return:
"""
data_payload = ''
api_result = ''
body = request.body
if not body:
return response_success()
data = json.loads(body)
# noinspection PyBroadException
try:
api_environment = APIEnvironment.objects.get(id=data['api_environment_id'])
except Exception:
return response_failed("30000", "请选择域名")
# 请求地址
api_url = api_environment.api_title + data['api_url']
api_url = RegularMatch(api_url, data['api_environment_id'])
if api_url[0] == "该变量数据库未找到":
return response_failed("4000", str(api_url[0] + api_url[1]))
api_headers = RegularMatch(data['api_headers'], data['api_environment_id'])
if api_headers[0] == "该变量数据库未找到":
return response_failed("4000", str(api_headers[0] + api_headers[1]))
json_header = api_headers.replace("\'", "\"")
if data['api_headers'] == '':
header = data['api_headers']
else:
try:
header = json.loads(json_header)
except json.decoder.JSONDecodeError:
return response_failed("30000", "header类型错误" + json_header)
logger.info(json_header)
# Params参数
api_parameter = {}
for api_parameters in data['api_parameter']:
if api_parameters['api_must_parameter'] == "true":
api_parameter.update({api_parameters['api_parameter_name']: api_parameters['api_parameter_value']})
else:
pass
api_parameter_data = RegularMatch(str(api_parameter), data['api_environment_id'])
if api_parameter_data[0] == "该变量数据库未找到":
return response_failed("4000", str(api_parameter_data[0] + api_parameter_data[1]))
data_parameter = api_parameter_data.replace("\'", "\"")
if data_parameter == '':
data_payload = api_parameter_data
logger.info(data_payload)
else:
try:
data_payload = json.loads(data_parameter)
logger.info(data_payload)
except json.decoder.JSONDecodeError:
return response_failed("30000", "参数类型错误" + data_payload)
api_parameter_body = RegularMatch(data['api_parameter_body'], data['api_environment_id'])
if api_parameter_body[0] == "该变量数据库未找到":
return response_failed("4000", str(api_parameter_body[0] + api_parameter_body[1]))
json_par = api_parameter_body.replace("\'", "\"")
if api_parameter_body == '':
payload = api_parameter_body
logger.info(payload)
else:
try:
payload = json.loads(json_par)
logger.info(payload)
except json.decoder.JSONDecodeError:
return response_failed("30000", "参数类型错误" + json_par)
r = InterfaceRequest(str(data['api_method']), str(data['api_parameter_types']), api_url, header, payload,
data_payload)
logger.info("测试用例名称: %s", data['api_test_case_name'])
logger.info("请求地址: %s", r.url)
logger.info("请求json数据: %s", payload)
logger.info("请求parameter数据: %s", data_payload)
logger.info("请求头: %s", r.headers)
logger.info("请求响应: %s", r.text)
logger.info(r.text)
if r == "请求超时":
return response_failed("30000", "接口超时", {'api_url': api_url,
"api_method": int(data['api_method']),
'api_header': header,
'api_body': payload,
'api_code': "请求超时",
'api_assert': "请求超时,断言失败",
'response_message': {"results": "请求超时"},
'response_time': 0,
'api_parameter_data': api_parameter})
# r.encoding = r.apparent_encoding
try:
response_message = r.json()
except json.decoder.JSONDecodeError:
return response_failed("30000", "接口返回结果类型错误非JSON格式", {'api_url': api_url,
"api_method": int(data['api_method']),
'api_header': header,
'api_body': payload,
'api_code': str(r.status_code),
'response_message': r.text,
'response_time': str(r.elapsed.total_seconds()),
'api_parameter_data': api_parameter})
# 断言
if data['api_assert_type'] == '':
result = "断言内容为空"
elif data['api_assert_type'] == 1:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"), r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(data['api_assert_text'].split())
assert r_text_data in r_text_test
result = "断言成功"
except Exception as e:
result = "断言失败: 响应内容中未包含 断言内容,断言内容: %s ,响应内容:%s" % (
data['api_assert_text'], r_text_test)
logger.error(result + str(e))
pass
elif data['api_assert_type'] == 2:
try:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"), r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(data['api_assert_text'].split())
assert r_text_data == r_text_test
result = "断言成功"
except Exception as e:
result = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (
data['api_assert_text'], r_text_test)
logger.error(result + str(e))
pass
elif data['api_assert_type'] == 3:
database = APIDatabase.objects.get(id=data['dataBase'])
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
sql = data['database_sql']
count = db.get_count(sql)
db.close()
if str(count) == str(data['api_assert_text']):
result = '断言成功'
else:
result = '断言失败,查询的数据是: %s' % str(count)
elif data['api_assert_type'] == 4:
try:
assert data['api_assert_text'] == str(r.status_code)
result = "断言成功"
except Exception as e:
result = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (data['api_assert_text'], str(r.status_code))
logger.error(result + str(e))
pass
api_variable_results = []
for api_parameter_extraction in data['api_parameter_extraction']:
if api_parameter_extraction['api_value_variable'] == "":
api_parameter_extraction_dict = {
"api_variable_results": "无参数提取",
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
}
api_variable_results.append(api_parameter_extraction_dict)
elif ApiParameterExtraction.objects.filter(
api_key_variable=api_parameter_extraction['api_key_variable']).count() >= 0:
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
logger.info('json转换失败(变量):' + str(e))
pass
v_text = api_parameter_extraction['api_value_variable'].split(".")
logger.info('这是提取' + str(v_text))
try:
api_result = ExtractParameters(v_text, api_result)
api_parameter_extraction_dict = {
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
"api_variable_results": str(api_result)
}
api_variable_results.append(api_parameter_extraction_dict)
except Exception as e:
logger.info('参数提取异常' + str(e))
api_parameter_extraction_dict = {
"api_variable_results": api_parameter_extraction['api_key_variable'],
"api_value_variable": api_parameter_extraction['api_value_variable'],
"api_key_variable": api_parameter_extraction['api_key_variable'],
}
api_variable_results.append(api_parameter_extraction_dict)
logger.info(api_variable_results)
return response_success({'api_url': api_url,
'api_header': header,
'api_body': payload,
'api_code': str(r.status_code),
'api_assert': str(result),
"api_method": int(data['api_method']),
'response_message': response_message,
'response_time': str(r.elapsed.total_seconds()),
'api_parameter_extraction': api_variable_results,
'api_parameter_data': api_parameter})
class UploadTestCases(View):
def post(self, request, *args, **kwargs):
"""
上传API测试用例-excel
"""
file_obj = request.FILES.get("file")
name = file_obj.name
fn = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
fn = fn + '-%d' % random.randint(0, 100)
path = os.path.join(settings.API_TEST_CASE_ROOT, fn + '-' + name)
with open(path, "wb") as f_write:
for line in file_obj:
f_write.write(line)
return response_success({"file": 'http://' + request.get_host() + "/api/api_test_case_excel/" + fn + '-' + name,
"result": "OK",
"fileName": name,
"path": path})
def put(self, request, *args, **kwargs):
"""
解析excel并创建测试用例
:api_excel_name: 接口excel名称
:param request:
:param args:
:param kwargs:
:return:
"""
upload_api_test_case_total = ""
api_assert_type = ""
api_parameter_types = ""
api_method = ""
body = request.body
if not body:
return response_success()
data = json.loads(body)
dir_test_case = settings.API_TEST_CASE_ROOT
dir_list = os.listdir(dir_test_case)
upload_results_list = []
upload_api_test_case_id = []
for api_test_case_excel in dir_list:
if api_test_case_excel == str(data['upload_case_address_name']):
api_excel = HandleExcel(dir_test_case + api_test_case_excel, 'Sheet1')
api_cases = api_excel.read_all_datas()
upload_api_test_case_total = len(api_cases)
for i in range(len(api_cases)):
time.sleep(0.5)
# 获取项目id
try:
api_project_id = APIProject.objects.filter(
api_project_name=str(api_cases[i]['项目名称']).replace("\n", ""))
except Exception as e:
return response_failed(3001, message="excel格式错误,请重新上传")
# 获取模块id
api_module_id = APIModule.objects.filter(api_project_id=api_project_id[0].id,
api_module_name=str(api_cases[i]['模块']).replace("\n", ""))
if ApiTestCase.objects.filter(api_test_case_name=str(api_cases[i]['测试用例名称']).replace("\n", ""),
api_module_id=api_module_id[0].id).count() > 0:
upload_results_dict = {
"test_case_name": str(api_cases[i]['测试用例名称']).replace("\n", ""),
"api_module_name": str(api_cases[i]['模块']).replace("\n", ""),
"api_url": str(api_cases[i]['请求地址']).replace("\n", ""),
"api_project_name": str(api_cases[i]['项目名称']).replace("\n", ""),
"error_reason": "用例名称重复,请重新上传"
}
upload_results_list.append(upload_results_dict)
for test_case_id in upload_api_test_case_id:
ApiTestCase.objects.get(id=test_case_id['api_test_case_id']).delete()
return response_failed(3000, {'status': 200, 'upload_results_list': upload_results_list,
'upload_api_test_case_total': upload_api_test_case_total,
'success_upload': '0', 'error_upload': len(upload_results_list),
"error_reason": "用例名称重复,请重新上传"})
# 获取域名id
api_environment_id = APIEnvironment.objects.filter(
api_title=(api_cases[i]['域名']).replace("\n", ""))
# 获取请求方式
if str(api_cases[i]['请求方式']).replace("\n", "").upper() == 'GET':
api_method = 1
elif str(api_cases[i]['请求方式']).replace("\n", "").upper() == 'POST':
api_method = 2
elif str(api_cases[i]['请求方式']).replace("\n", "").upper() == 'PUT':
api_method = 3
elif str(api_cases[i]['请求方式']).replace("\n", "").upper() == 'DELETE':
api_method = 4
# 获取body类型
# 1:form-data 2: json 3:x-www-form-urlencoded
if str(api_cases[i]['body类型']).replace("\n", "").upper() == 'FORM-DATA':
api_parameter_types = 1
elif str(api_cases[i]['body类型']).replace("\n", "").upper() == 'JSON':
api_parameter_types = 2
elif str(api_cases[i]['body类型']).replace("\n", "").upper() == 'X-WWW-FORM-URLENCODED':
api_parameter_types = 3
# 1:包含contains 2: 匹配MATHCHES 3:数据库校验SQL 4:CODE
if str(api_cases[i]['断言类型']).replace("\n", "").upper() == 'CONTAINS':
api_assert_type = 1
elif str(api_cases[i]['断言类型']).replace("\n", "").upper() == 'MATHCHES':
api_assert_type = 2
elif str(api_cases[i]['断言类型']).replace("\n", "").upper() == 'SQL':
api_assert_type = 3
elif str(api_cases[i]['断言类型']).replace("\n", "").upper() == 'CODE':
api_assert_type = 4
# 获取数据库
api_data_base_id = APIDatabase.objects.filter(
api_database_title=str(api_cases[i]['数据库环境']).replace("\n", ""))
if str(api_cases[i]['数据库环境']).replace("\n", "") == "None":
data_base_id = ""
else:
data_base_id = api_data_base_id[0].id
if str(api_cases[i]['数据库语句']).replace("\n", "") == "None":
database_sql = ""
else:
database_sql = str(api_cases[i]['数据库语句']).replace("\n", "")
# 获取body
if str(api_cases[i]['body']).replace("\n", "") == 'None':
api_parameter_body = {}
else:
api_parameter_body = str(api_cases[i]['body']).replace("\n", "")
# 获取请求头
if str(api_cases[i]['请求头']).replace("\n", "") == 'None':
header = {}
else:
header = str(api_cases[i]['请求头']).replace("\n", "")
# 获取断言内容
if str(api_cases[i]['断言内容']).replace("\n", "") == "None":
api_assert_text = ""
else:
api_assert_text = str(api_cases[i]['断言内容']).replace("\n", "")
# 创建测试用例
api_test_case = ApiTestCase.objects.create(
api_test_case_name=str(api_cases[i]['测试用例名称']).replace("\n", ""),
api_module_id=api_module_id[0].id,
api_documentation=api_cases[i]['接口文档地址'],
api_environment_id=api_environment_id[0].id,
api_method=api_method,
api_url=str(api_cases[i]['请求地址']).replace("\n", ""),
api_parameter_types=api_parameter_types,
api_headers=header,
api_parameter_body=api_parameter_body,
api_assert_type=api_assert_type,
dataBase_id=data_base_id,
database_sql=database_sql,
api_assert_text=api_assert_text
)
# 获取变量名称
variable_name = str(api_cases[i]['变量名称']).split(',')
# 获取变量提取表达式
api_value_variable = str(api_cases[i]['提取表达式']).split(',')
variable_name_list = []
for value in variable_name:
if ApiParameterExtraction.objects.filter(api_key_variable=value).count() > 0:
variable_name_dict = {
"api_key_variable": "变量名称重复" + str(value)
}
variable_name_list.append(variable_name_dict)
upload_results_dict = {
"test_case_name": str(api_cases[i]['测试用例名称']).replace("\n", ""),
"api_module_name": str(api_cases[i]['模块']).replace("\n", ""),
"api_url": str(api_cases[i]['请求地址']).replace("\n", ""),
"api_project_name": str(api_cases[i]['项目名称']).replace("\n", ""),
"error_reason": "参数变量重复,请重新上传"
}
upload_results_list.append(upload_results_dict)
for test_case_id in upload_api_test_case_id:
ApiTestCase.objects.get(id=test_case_id['api_test_case_id']).delete()
return response_failed(3000, {'status': 200, 'upload_results_list': upload_results_list,
'upload_api_test_case_total': upload_api_test_case_total,
'success_upload': '0',
'error_upload': len(upload_results_list),
"error_reason": "参数变量重复,请重新上传"})
elif value == "None":
variable_name_list = []
else:
variable_name_dict = {
"api_key_variable": str(value)
}
variable_name_list.append(variable_name_dict)
for v in range(len(variable_name_list)):
if len(variable_name_list) == 0:
pass
else:
variable_name_list[v]['api_value_variable'] = api_value_variable[v]
ApiParameterExtraction.objects.create(
api_key_variable=variable_name_list[v]['api_key_variable'],
api_value_variable=api_value_variable[v], api_test_case_id=api_test_case.id)
# data参数 创建
if str(api_cases[i]['Params']).replace("\n", "") == "None":
ApiParameterData.objects.create(api_must_parameter="false",
api_test_case_id=api_test_case.id)
else:
params = json.loads(str(api_cases[i]['Params']).replace("\n", ""))
for key in params:
ApiParameterData.objects.create(api_parameter_name=key, api_must_parameter="true",
api_parameter_value=params[key],
api_test_case_id=api_test_case.id)
upload_api_test_case_id.append({'api_test_case_id': api_test_case.id})
success_upload = upload_api_test_case_total - len(upload_results_list)
return response_success({'status': 200, 'upload_results_list': upload_results_list,
'upload_api_test_case_total': upload_api_test_case_total,
'success_upload': success_upload, 'error_upload': len(upload_results_list)})
class DownloadApiCaseTemplate(View):
def get(self, request, *args, **kwargs):
"""
下载API用例模板
:param request:
:param args:
:param kwargs:
:return:
"""
logger.info("API测试用例地址:" + settings.API_TEMPLATE)
file = open(settings.API_TEMPLATE, 'rb')
response = FileResponse(file)
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;' + ' filename=' + "ApiTestCaseTemplate.xlsx"
return response
# -*- coding: utf-8 -*-
# @Time : 2022/7/14 14:41
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 14:46
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 14:47
# @Author : wangyinghao
# @Site :
# @File : api_test_plan_list_view.py
# @Software: PyCharm
from django.views.generic import View
from automated_main.utils.http_format import response_success
from automated_main.models.api_automation.api_test_plan import ApiTestPlan
import arrow
class ApiTestPlanListView(View):
def get(self, request, api_management_id, *args, **kwargs):
"""
代表获取所有API测试任务
:param request:
:param api_management_id: API项目id
:param args:
:param kwargs:
:return:
"""
status = None
api_test_plan_data = ApiTestPlan.objects.filter(api_management_id=api_management_id).order_by('-id')
api_test_plan_list = []
for api_test_plan in api_test_plan_data:
if api_test_plan.status == 0:
status = "未执行"
elif api_test_plan.status == 1:
status = "执行中"
elif api_test_plan.status == 2:
status = "已完成"
api_task_dict = {
"id": api_test_plan.id,
"api_test_plan_describe": api_test_plan.api_test_plan_describe,
"cases": api_test_plan.cases,
"api_test_plan_name": api_test_plan.api_test_plan_name,
"api_send_email": api_test_plan.api_send_email,
"api_send_enterprise_wechat": api_test_plan.api_send_enterprise_wechat,
"api_environment_id": api_test_plan.api_environment_id,
"database_id": api_test_plan.database_id,
"timing_task_status": api_test_plan.timing_task_status,
"time_interval_seconds": api_test_plan.time_interval_seconds,
"time_interval_hours": api_test_plan.time_interval_hours,
"time_interval_minutes": api_test_plan.time_interval_minutes,
"time_interval_day": api_test_plan.time_interval_day,
"end_time": api_test_plan.end_time,
"starting_time": api_test_plan.starting_time,
"status": status,
"update_time": arrow.get(str(api_test_plan.update_time)).format('YYYY-MM-DD HH:mm:ss'),
"create_time": arrow.get(str(api_test_plan.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
api_test_plan_list.append(api_task_dict)
return response_success(api_test_plan_list)
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 14:46
# @Author : wangyinghao
# @Site :
# @File : api_test_plan_view.py
# @Software: PyCharm
from django.views.generic import View
import json
from datetime import datetime
from django.forms import model_to_dict
from automated_main.utils.http_format import response_success, response_failed
from automated_main.exception.my_exception import MyException
from automated_main.models.api_automation.api_test_plan import ApiTestPlan, APITestPlanResult, APITestPlanResultAssociated
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCase
from automated_main.form.api_test_plan import ApiTestPlanForm
from automated_main.models.api_automation.api_management import ApiManagement
from automated_main.view.api_automation.api_test_plan.extend.test_plan_thread import TaskThread
from django.core.paginator import Paginator
import arrow
import logging
logger = logging.getLogger('django')
class APITestPlanSuspended(View):
def post(self, request, *args, **kwargs):
"""
暂停接口计划
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
api_task = ApiTestPlan.objects.get(id=data["api_test_plan_id"])
api_task.status = 2
api_task.save()
return response_success("暂停API测试计划成功")
class ApiTestPlanView(View):
def get(self, request, api_test_plan_id, *args, **kwargs):
"""
获取单个API测试计划
:param request:
:param api_test_plan_id: API测试计划ID
:param args:
:param kwargs:
:return:
"""
api_test_plan = ApiTestPlan.objects.get(id=api_test_plan_id)
return response_success(model_to_dict(api_test_plan))
def delete(self, request, api_test_plan_id, *args, **kwargs):
"""
删除API测试计划
:param request:
:param api_test_plan_id:任务ID
:param args:
:param kwargs:
:return:
"""
ApiTestPlan.objects.get(id=api_test_plan_id).delete()
return response_success("删除API测试计划成功")
def put(self, request, *args, **kwargs):
"""
创建API测试任务
:param request:
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiTestPlanForm(data)
if form.is_valid():
if data['api_test_plan_id'] == 0:
ApiTestPlan.objects.create(**form.cleaned_data)
return response_success("创建API测试任务成功")
else:
raise MyException()
def post(self, request, api_test_plan_id, *args, **kwargs):
"""
更改API测试计划
:param request:
:param api_test_plan_id: API测试任务ID
:param args:
:param kwargs:
:return:
"""
body = request.body
if not body:
return response_success()
data = json.loads(body)
form = ApiTestPlanForm(data)
if form.is_valid():
api_test_plan = ApiTestPlan.objects.get(id=api_test_plan_id)
api_test_plan.api_test_plan_name = data['api_test_plan_name']
api_test_plan.api_test_plan_describe = data['api_test_plan_describe']
api_test_plan.cases = data['cases']
api_test_plan.api_management_id = data['api_management_id']
api_test_plan.api_send_email = data['api_send_email']
api_test_plan.api_send_enterprise_wechat = data['api_send_enterprise_wechat']
api_test_plan.api_environment_id = data['api_environment_id']
api_test_plan.database_id = data['database_id']
api_test_plan.time_interval_seconds = data['time_interval_seconds']
api_test_plan.time_interval_hours = data['time_interval_hours']
api_test_plan.time_interval_minutes = data['time_interval_minutes']
api_test_plan.time_interval_day = data['time_interval_day']
api_test_plan.end_time = data['end_time']
api_test_plan.starting_time = data['starting_time']
api_test_plan.timing_task_status = data['timing_task_status']
api_test_plan.update_time = datetime.now()
api_test_plan.save()
return response_success("编辑API测试计划成功")
else:
raise MyException()
class GetScenariosCaseTree(View):
def get(self, request, api_management_id, *args, **kwargs):
"""
获取Api测试用例树形结构
:param request:
:param api_management_id:
:param args:
:param kwargs:
:return:
"""
api_management_data = ApiManagement.objects.filter(id=api_management_id)
data_list = []
for api_management in api_management_data:
api_management_dict = {
"api_project_name": api_management.name,
"isParent": True
}
api_scenarios_case_list = []
api_scenarios_case_data = ApiScenariosCase.objects.filter(api_management_id=api_management_id)
for api_scenarios_case in api_scenarios_case_data:
api_case_dict = {
"api_scenarios_case_name": api_scenarios_case.api_scenarios_case_name,
"isParent": False,
"api_scenarios_case_id": api_scenarios_case.id
}
api_scenarios_case_list.append(api_case_dict)
api_management_dict["children"] = api_scenarios_case_list
data_list.append(api_management_dict)
return response_success(data_list)
class PerformApiPlan(View):
def post(self, request, api_test_plan_id, *args, **kwargs):
"""
执行当前API测试计划
:param request:
:param api_test_plan_id:
:param args:
:param kwargs:
:return:
"""
if api_test_plan_id == "":
return response_failed({"status": 10200, "message": "api_test_plan_id is null"})
# 1.在执行线程之前,判断当前任务是否在执行
api_tasks = ApiTestPlan.objects.get(id=api_test_plan_id)
if api_tasks.status == 1:
return response_failed({"status": 10200, "message": "当前该测试任务正在执行!"})
else:
# 2. 修改任务的状态为:1-执行中
api_tasks = ApiTestPlan.objects.get(id=api_test_plan_id)
api_tasks.status = 1
api_tasks.save()
# 通过多线程运行测试任务
TaskThread(api_test_plan_id).run()
return response_success({"status": 10200, "message": "任务开始执行!"})
def get(self, request, *args, **kwargs):
"""
执行所有API测试计划
:param request:
:param args:
:param kwargs:
:return:
"""
api_test_plan = ApiTestPlan.objects.filter(timing_task_status="true")
for plan in api_test_plan:
# 1.在执行线程之前,判断当前有没有任务在执行
api_tasks = ApiTestPlan.objects.get(id=plan.id)
if api_tasks.status == 1:
logger.info("该任务正在执行中:" + plan.api_test_task_name)
continue
else:
# 2. 修改任务的状态为:1-执行中
api_plan = ApiTestPlan.objects.get(id=plan.id)
api_plan.status = 1
api_plan.save()
# 通过多线程运行测试任务
TaskThread(plan.id).run()
return response_success({"status": 10200, "message": "测试计划开始执行!"})
class CheckApiPlanResultList(View):
def get(self, request, api_test_plan_id, size_page, page, *args, **kwargs):
"""
查看API测试计划报告列表
:param page:
:param size_page:
:param request:
:param api_test_plan_id:
:param args:
:param kwargs:
:return:
"""
if api_test_plan_id == "":
return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
result_data = APITestPlanResult.objects.filter(api_test_plan_id=api_test_plan_id).order_by('-create_time')
data = []
for i in result_data:
result = {
"id": i.id,
"api_test_result_name": i.api_test_result_name,
"create_time": i.create_time,
"api_error_total_number": i.api_error_total_number,
"api_successful_total_number": i.api_successful_total_number,
"api_total_number": i.api_total_number
}
data.append(result)
api_result_total = len(data)
p = Paginator(data, size_page)
if int(page) > int(p.num_pages):
page1 = p.page(p.num_pages)
current_page = page1.object_list
else:
page1 = p.page(page)
current_page = page1.object_list
return response_success({'status': 10102, 'data': current_page, 'api_result_total': api_result_total})
class CheckApiResult(View):
def get(self, request, api_test_result_id, size_page, page, *args, **kwargs):
"""
查看任务--测试报告列表--测试结果列表
:param size_page: 展示条数
:param page: 页数
:param request:
:param api_test_result_id:
:param args:
:param kwargs:
:return:
"""
if api_test_result_id == "":
return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
r = APITestPlanResultAssociated.objects.filter(api_result_id=api_test_result_id)
data = []
for i in r:
result = {
"id": i.id,
"api_test_case_name": i.api_test_case_name,
"api_task_name": i.api_test_plan.api_test_plan_name,
"api_business_test_name": i.api_business_test_name,
"api_error": i.api_error,
"api_successful": i.api_successful,
"abnormal": i.abnormal,
"json_extract_variable_conversion": i.json_extract_variable_conversion,
"api_assertion_results": i.api_assertion_results,
"api_request_results": i.api_request_results,
"api_result_id": i.api_result_id,
"api_task_id": i.api_test_plan_id,
"create_time": arrow.get(str(i.create_time)).format('YYYY-MM-DD HH:mm:ss'),
}
data.append(result)
p = Paginator(data, size_page)
if int(page) > int(p.num_pages):
page1 = p.page(p.num_pages)
current_page = page1.object_list
else:
page1 = p.page(page)
current_page = page1.object_list
api_result = APITestPlanResult.objects.get(id=api_test_result_id)
case_result_total = [int(api_result.api_successful_total_number), int(api_result.api_error_total_number)]
return response_success({'status': 10102, 'data': current_page, "case_result_total": case_result_total})
def post(self, request, api_test_case_result_id, *args, **kwargs):
"""
查看任务--测试报告列表--测试结果列表--单独测试用例报告
:param request:
:param api_test_case_result_id:API测试结果关联表的ID
:param args:
:param kwargs:
:return:
"""
if api_test_case_result_id == "":
return response_failed({"status": 10102, "message": "api_test_case_result_id不能为空"})
r = APITestPlanResultAssociated.objects.filter(id=api_test_case_result_id)
data = []
for i in r:
result = {
"id": i.id,
"api_test_case_name": i.api_test_case_name,
"api_task_name": i.api_test_plan.api_test_plan_name,
"api_business_test_name": i.api_business_test_name,
"api_error": i.api_error,
"api_successful": i.api_successful,
"abnormal": i.abnormal,
"json_extract_variable_conversion": i.json_extract_variable_conversion,
"api_assertion_results": i.api_assertion_results,
"api_request_results": i.api_request_results,
"api_result_id": i.api_result_id,
"api_task_id": i.api_test_plan_id,
"create_time": i.create_time,
"api_variable_results": i.api_variable_results,
"api_header": i.api_header,
"api_url": i.api_url,
"api_body": i.api_body
}
data.append(result)
return response_success({'status': 10102, 'data': data})
def delete(self, request, api_test_result_id, *args, **kwargs):
"""
查看任务--测试报告列表--删除测试报告
:param request:
:param api_test_result_id:API测试结果关联表的ID
:param args:
:param kwargs:
:return:
"""
if api_test_result_id == "":
return response_failed({"status": 10102, "message": "api_test_result_id不能为空"})
APITestPlanResult.objects.get(id=api_test_result_id).delete()
return response_success("删除测试报告成功")
class CheckApiResultErrorList(View):
def get(self, request, api_test_result_id, size_page, page, *args, **kwargs):
"""
查看任务--测试报告列表--测试结果列表
:param size_page: 展示条数
:param page: 页数
:param request:
:param api_test_result_id:
:param args:
:param kwargs:
:return:
"""
if api_test_result_id == "":
return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
r = APITestPlanResultAssociated.objects.filter(api_result_id=api_test_result_id, api_error=1)
data = []
for i in r:
result = {
"id": i.id,
"api_test_case_name": i.api_test_case_name,
"api_task_name": i.api_test_plan.api_test_plan_name,
"api_business_test_name": i.api_business_test_name,
"api_error": i.api_error,
"api_successful": i.api_successful,
"abnormal": i.abnormal,
"json_extract_variable_conversion": i.json_extract_variable_conversion,
"api_assertion_results": i.api_assertion_results,
"api_request_results": i.api_request_results,
"api_result_id": i.api_result_id,
"api_task_id": i.api_test_plan_id,
"create_time": arrow.get(str(i.create_time)).format('YYYY-MM-DD HH:mm:ss')
}
data.append(result)
p = Paginator(data, size_page)
if int(page) > int(p.num_pages):
page1 = p.page(p.num_pages)
current_page = page1.object_list
else:
page1 = p.page(page)
current_page = page1.object_list
api_result = APITestPlanResult.objects.get(id=api_test_result_id)
case_result_total = [int(api_result.api_successful_total_number), int(api_result.api_error_total_number)]
return response_success({'status': 10102, 'data': current_page, "case_result_total": case_result_total})
\ No newline at end of file
# -*- coding: utf-8 -*-
# @Time : 2022/7/21 19:13
# @Author : wangyinghao
# @Site :
# @File : __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/11/25 19:56
# @Author : wangyinghao
# @Site :
# @File : run_test_plan_task.py
# @Software: PyCharm
import django
import json
import os
import re
import sys
from os.path import dirname, abspath
BASE_DIR = dirname(dirname(dirname(abspath(__file__))))
BASE_PATH = BASE_DIR.replace("\\", "/")
sys.path.append(BASE_PATH)
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
sys.path.extend(['/home/AutomatedTestPlatform'])
# project_name 项目名称
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AutomatedTestPlatform.settings")
django.setup()
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesParameterExtraction
from automated_main.models.api_automation.api_test_plan import APITestPlanResultAssociated
from automated_main.utils.handle_db import HandleDB
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.api_utils import RegularMatch
from automated_main.utils.api_utils import InterfaceRequest
import logging
import ast
logger = logging.getLogger('django')
logger.info("运行测试文件:" + BASE_PATH)
# 定义扩展的目录
EXTEND_DIR = BASE_PATH + "/api_test_plan/extend/"
logger.info("地址信息" + EXTEND_DIR)
def new_test_run_cases(case_id):
for case in case_id:
api_test_case_id = (case['api_test_case_id'])
api_test_case_name = (case['api_test_case_name'])
api_url = (case['api_url'])
api_method = (case['api_method'])
api_parameter_types = (case['api_parameter_types'])
api_headers = (case['api_headers'])
api_parameter_body = (case['api_parameter_body'])
api_assert_type = (case['api_assert_type'])
api_parameter_extraction = (case['api_parameter_extraction'])
parameter_data = (case['parameter_data'])
api_assert_text = (case['api_assert_text'])
api_result_id = (case['api_result_id'])
api_task_id = (case['api_task_id'])
database_id = (case['dataBase_id'])
database_sql = (case['database_sql'])
api_business_test_name = (case['api_scenarios_case_name'])
api_environment_id = (case['api_environment_id'])
api_assertion_results = ""
api_error = ""
api_successful = ""
api_variable_results = ""
abnormal = ""
json_loads = ""
try:
api_url = RegularMatch(api_url, api_environment_id, "1", regular="new")
# if "${" in api_url and "}" in api_url:
# key = re.findall(r"\${(.+?)}", api_url)
# for a in range(len(key)):
# key1 = "${" + key[a] + "}"
#
# api_global_variable = APIGlobalVariable.objects.filter(api_global_variable_name=key1,
# api_environment_id=api_environment_id)
# if api_global_variable.count() > 0:
# variable = api_global_variable[0].api_global_variable_value
# api_url = api_url.replace(key1, variable)
# else:
# value_variable = ApiParameterExtraction.objects.filter(api_key_variable=key1)
# variable = value_variable[0].api_variable_results
# api_url = api_url.replace(key1, variable)
if api_headers == "{}" or "":
header_dict = {}
else:
api_headers = RegularMatch(api_headers, api_environment_id, "1", regular="new")
# if "${" in api_headers and "}" in api_headers:
# key = re.findall(r"\${(.+?)}", api_headers)
# for b in range(len(key)):
# key1 = "${" + key[b] + "}"
#
# api_global_variable = APIGlobalVariable.objects.filter(api_global_variable_name=key1,
# api_environment_id=api_environment_id)
# if api_global_variable.count() > 0:
# variable = api_global_variable[0].api_global_variable_value
# api_headers = api_headers.replace(key1, variable)
# else:
# value_variable = ApiParameterExtraction.objects.filter(api_key_variable=key1)
# variable = value_variable[0].api_variable_results
# api_headers = api_headers.replace(key1, variable)
header = api_headers.replace("\'", "\"")
header_dict = json.loads(header)
if api_parameter_body == "{}" or "":
api_parameter_body_dict = {}
else:
api_parameter_body = RegularMatch(api_parameter_body, api_environment_id, "1", regular="new")
# if "${" in api_parameter_body and "}" in api_parameter_body:
# key = re.findall(r"\${(.+?)}", api_parameter_body)
# for b in range(len(key)):
# key1 = "${" + key[b] + "}"
#
# api_global_variable = APIGlobalVariable.objects.filter(api_global_variable_name=key1,
# api_environment_id=api_environment_id)
# if api_global_variable.count() > 0:
# variable = api_global_variable[0].api_global_variable_value
# api_parameter_body = api_parameter_body.replace(key1, variable)
# else:
#
# value_variable = ApiParameterExtraction.objects.filter(api_key_variable=key1)
# variable = value_variable[0].api_variable_results
# api_parameter_body = api_parameter_body.replace(key1, variable)
api_parameter = api_parameter_body.replace("\'", "\"")
api_parameter_body_dict = json.loads(api_parameter)
if parameter_data == "{}" or "":
data_payload = {}
else:
parameter_data_task = RegularMatch(str(parameter_data), api_environment_id, "1", regular="new")
data_payload = ast.literal_eval(parameter_data_task)
# if "${" in parameter_data and "}" in parameter_data:
# key = re.findall(r"\${(.+?)}", parameter_data)
# for b in range(len(key)):
# key1 = "${" + key[b] + "}"
#
# api_global_variable = APIGlobalVariable.objects.filter(api_global_variable_name=key1,
# api_environment_id=api_environment_id)
# if api_global_variable.count() > 0:
# variable = api_global_variable[0].api_global_variable_value
# parameter_data = parameter_data.replace(key1, variable)
# else:
#
# value_variable = ApiParameterExtraction.objects.filter(api_key_variable=key1)
# variable = value_variable[0].api_variable_results
# parameter_data = parameter_data.replace(key1, variable)
r = InterfaceRequest(str(api_method), str(api_parameter_types), api_url, header_dict,
api_parameter_body_dict, data_payload)
logger.info("测试用例名称: %s", api_test_case_name)
logger.info("请求地址: %s", r.url)
logger.info("请求json数据: %s", api_parameter_body_dict)
logger.info("请求parameter数据: %s", data_payload)
logger.info("请求头: %s", r.headers)
logger.info("请求响应: %s", r.text)
if r == "请求超时":
api_error = 1
api_successful = 0
APITestPlanResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results={"results": "请求超时,断言失败"},
api_variable_results={"results": "请求超时无法提取变量"},
api_request_results={"results": "请求超时"},
api_result_id=api_result_id,
api_test_plan_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=api_url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
else:
# r.encoding = r.apparent_encoding
if api_assert_type == '':
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
elif api_assert_type == 1:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(api_assert_text.split())
try:
assert r_text_data in r_text_test
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error(
"断言失败,用例名称是:" + api_test_case_name + "断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text) + str(e))
api_assertion_results = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 2:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(api_assert_text.split())
try:
assert r_text_data == r_text_test
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error(
"断言失败,用例名称是:" + api_test_case_name + "断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text) + str(e))
api_assertion_results = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 3:
database = APIDatabase.objects.get(id=database_id)
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
count = db.get_count(database_sql)
db.close()
if str(count) == str(api_assert_text):
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
else:
logger.error("断言失败,用例名称是:" + api_test_case_name + '断言失败,查询的数据是: %s' % str(count))
api_assertion_results = '断言失败,查询的数据是: %s' % str(count)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 4:
try:
assert str(api_assert_text) == str(r.status_code)
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error("断言失败,用例名称是:" + api_test_case_name + "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (
api_assert_text, str(r.status_code)) + str(e))
api_assertion_results = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (api_assert_text, str(r.status_code))
api_error = 1
api_successful = 0
pass
if ApiInterfacesParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).count() > 0:
ApiInterfacesParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).delete()
for api_parameter_extractions in api_parameter_extraction:
if api_parameter_extractions['api_value_variable'] == "":
pass
else:
v_text = api_parameter_extractions['api_value_variable'].split(".")
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
json_loads = "提取变量json.loads(r.text) 失败:" + str(e)
logger.error("提取变量json.loads(r.text) 失败:" + str(e))
pass
try:
for a in v_text:
if "[" in a and "]" in a:
variable_1 = a.split('[')[0]
variable_2 = a.split('[')[1].split(']')[0]
if variable_1 == "":
api_result = api_result[0]
else:
api_result = api_result[variable_1][int(variable_2)]
else:
if a == "0":
api_result = api_result[int(a)]
else:
api_result = api_result[a]
api_variable_results = str(api_result)
except Exception as e:
api_variable_results = api_parameter_extractions['api_key_variable']
pass
logger.info("自定义变量表中有该case_id")
ApiInterfacesParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_variable_results,
api_value_variable=
api_parameter_extractions[
'api_value_variable'],
api_key_variable=api_parameter_extractions[
'api_key_variable'])
else:
logger.info("自定义变量表中 无 该 case_id")
for api_parameter_extractions in api_parameter_extraction:
if api_parameter_extractions['api_key_variable'] == "":
pass
else:
v_text = api_parameter_extractions['api_value_variable'].split(".")
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
json_loads = "提取变量json.loads(r.text) 失败:" + str(e)
logger.error("提取变量json.loads(r.text) 失败:" + str(e))
pass
try:
for a in v_text:
if "[" in a and "]" in a:
variable_1 = a.split('[')[0]
variable_2 = a.split('[')[1].split(']')[0]
api_result = api_result[variable_1][int(variable_2)]
else:
api_result = api_result[a]
api_variable_results = str(api_result)
except Exception as e:
logger.info(str(api_test_case_name) + " 参数提取失败" + api_parameter_extractions[
'api_key_variable'] + str(e))
api_variable_results = api_parameter_extractions['api_key_variable']
logger.error(api_variable_results)
pass
if ApiInterfacesParameterExtraction.objects.filter(
api_key_variable=api_parameter_extractions['api_key_variable']).count() > 0:
api_parameter_extraction_list = (
str(api_parameter_extractions['api_key_variable']) + "变量名称重复,请重新填写")
else:
ApiInterfacesParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=
api_parameter_extractions[
'api_variable_results'],
api_value_variable=api_variable_results,
api_key_variable=
api_parameter_extractions[
'api_key_variable'])
api_parameter_extraction = ApiInterfacesParameterExtraction.objects.filter(
api_test_case_id=api_test_case_id)
api_parameter_extraction_list = []
if api_parameter_extraction.count() > 0:
for api_parameter_extractions in api_parameter_extraction:
api_parameter_extraction_dict = {
"api_key_variable": api_parameter_extractions.api_key_variable,
"api_variable_results": api_parameter_extractions.api_variable_results
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
APITestPlanResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=r.json(),
api_result_id=api_result_id,
api_test_plan_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=r.url,
api_body=api_parameter_body_dict,
api_header=header_dict
)
except Exception as e:
abnormal = str(e)
if api_assertion_results == "断言成功":
api_error = 0
api_successful = 1
APITestPlanResultAssociated.objects.create(api_test_case_name=api_test_case_name,
api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=r.text.encode().decode("unicode_escape"),
api_result_id=api_result_id,
api_test_plan_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=r.url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
else:
api_error = 1
api_successful = 0
APITestPlanResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=r.text.encode().decode("unicode_escape"),
api_result_id=api_result_id,
api_test_plan_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=api_url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
continue
# -*- coding: utf-8 -*-
# @Time : 2021/11/23 11:21
# @Author : wangyinghao
# @Site :
# @File : test_plan_thread.py
# @Software: PyCharm
import os
import json
import threading
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AutomatedTestPlatform.settings")
django.setup()
from time import sleep
from automated_main.models.api_automation.api_scenarios_case import ApiScenariosCase, ApiScenariosCaseAssociated
from automated_main.models.api_automation.api_test_plan import ApiTestPlan
from automated_main.models.api_automation.api_test_plan import APITestPlanResult
from automated_main.models.api_automation.api_interfaces_case import ApiInterfacesCase, ApiInterfacesParameterExtraction, ApiInterfacesParameterData
from automated_main.models.api_automation.api_test_plan import APITestPlanResultAssociated
from automated_main.utils.send_email import SendEmail
from automated_main.utils.send_enterprise_wechat import SendEnterpriseWechatMsg
from AutomatedTestPlatform import settings
from automated_main.view.api_automation.api_test_plan.extend.run_test_plan_task import new_test_run_cases
import time
import logging
BASE_PATH = settings.BASE_DIR.replace("\\", "/")
EXTEND_DIR = BASE_PATH + "/automated_main/view/api_automation/api_test_plan/extend/"
# EXTEND_DIR = BASE_PATH + "\\automated_main\\view\\api_automation\\api_test_task\\extend\\"
logger = logging.getLogger('django')
class TaskThread:
def __init__(self, task_id):
self.tid = task_id
def run_cases(self):
logger.info("运行某一个任务下面的所有测试用例")
api_task = ApiTestPlan.objects.get(id=self.tid)
# 1. 拿到任务对应用例的列表
api_case_list = json.loads(api_task.cases)
logger.info("拿到任务对应用例的列表" + api_task.cases)
now = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
api_result = APITestPlanResult.objects.create(
api_test_plan_id=self.tid,
api_test_result_name=now,
api_environment_id=api_task.api_environment.id
)
api_result_id = api_result.id
# 2. 获取API用例数据
for sid in api_case_list:
logger.info(sid)
api_scenarios_case = ApiScenariosCase.objects.get(id=sid)
api_associated = ApiScenariosCaseAssociated.objects.filter(sid_id=sid)
data_list = []
for api_associates in api_associated:
api_test_case = ApiInterfacesCase.objects.get(id=api_associates.interfaces_case_id)
api_parameter_extraction = ApiInterfacesParameterExtraction.objects.filter(
api_test_case_id=api_associates.interfaces_case_id)
parameter_data = ApiInterfacesParameterData.objects.filter(api_test_case_id=api_associates.interfaces_case_id)
api_parameter_extraction_list = []
api_parameter_dict = {}
for api_parameters in parameter_data:
if api_parameters.api_must_parameter == "true":
api_parameter_dict.update(
{api_parameters.api_parameter_name: api_parameters.api_parameter_value})
else:
pass
for api_parameter_extractions in api_parameter_extraction:
api_parameter_extraction_dict = {
"api_value_variable": api_parameter_extractions.api_value_variable,
"api_key_variable": api_parameter_extractions.api_key_variable,
"api_variable_results": api_parameter_extractions.api_variable_results,
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
api_associated_dict = {
"api_scenarios_case_name": api_scenarios_case.api_scenarios_case_name,
"api_result_id": api_result.id,
"api_task_id": self.tid,
"api_test_case_id": api_associates.interfaces_case_id,
"api_test_case_name": api_test_case.api_interfaces_case_name,
"api_method": api_test_case.api_method,
"dataBase_id": api_task.database_id,
"database_sql": api_test_case.database_sql,
"api_url": api_task.api_environment.api_title + api_test_case.api_url,
"api_parameter_types": api_test_case.api_parameter_types,
"api_headers": api_test_case.api_headers,
"parameter_data": api_parameter_dict,
"api_parameter_body": api_test_case.api_parameter_body,
"api_assert_type": api_test_case.api_assert_type,
"api_assert_text": api_test_case.api_assert_text,
"api_parameter_extraction": api_parameter_extraction_list,
"api_environment_id": api_task.api_environment.id,
"case_steps": int(api_associates.case_steps)
}
data_list.append(api_associated_dict)
data_list_sorting = sorted(data_list, key=lambda x: x['case_steps'])
# 3.这里就可以获取到业务测试用例 data_list_sorting 赋值到 new_test_run_cases中
new_test_run_cases(data_list_sorting)
api_total_number = APITestPlanResultAssociated.objects.filter(api_result_id=api_result.id).count()
api_error_total_number = APITestPlanResultAssociated.objects.filter(api_result_id=api_result.id,
api_error=1).count()
api_successful_total_number = APITestPlanResultAssociated.objects.filter(api_result_id=api_result.id,
api_successful=1).count()
api_test_result = APITestPlanResult.objects.get(id=api_result.id)
api_test_result.api_error_total_number = api_error_total_number
api_test_result.api_successful_total_number = api_successful_total_number
api_test_result.api_total_number = api_total_number
api_test_result.save()
# 4. 修改任务的状态,执行完成
api_task.status = 2
api_task.save()
# 取小数后2位,通过率
pass_result = "%.2f%%" % (api_successful_total_number / api_total_number * 100)
fail_result = "%.2f%%" % (api_error_total_number / api_total_number * 100)
user_list = api_task.api_send_email
sub = "接口自动化测试报告-%s" % api_task.api_test_plan_name
api_result = APITestPlanResultAssociated.objects.filter(api_result_id=api_result.id, api_error=1)
content = "这次一共测试%s个接口,通过个数为%s,失败个数为%s,通过率为%s,失败率为%s \n" % (
api_total_number, api_successful_total_number, api_error_total_number, pass_result, fail_result)
error_case = ""
for a in api_result:
case_result = "业务测试用例名称:" + a.api_business_test_name + ", 测试用例名称:" + a.api_test_case_name + \
", 断言结果:" + a.api_assertion_results
error_case += case_result + ",\n"
# 5.发送邮件
if api_task.api_send_email == "" or None:
logger.info("该任务无需发送邮件,未填写邮箱")
else:
sen = SendEmail()
sen.send_mail(user_list, sub, content + error_case)
# 6 发送企业微信
if api_error_total_number > 0:
if api_task.api_send_enterprise_wechat == 1:
ENV_PROFILE = os.getenv("ENV")
if ENV_PROFILE == "SERVER":
result_host = 'http://172.16.0.82:8089'
elif ENV_PROFILE == "1":
result_host = 'http://localhost:8080'
api_task_result = result_host + "/#/api_test_plan_result?apiResultId=" + str(api_result_id)
wx_url = ""
# 发送企业微信
# a = SendEnterpriseWechatMsg()
# a.send_msg(wx_url, api_total_number, pass_result, api_successful_total_number, api_error_total_number,
# api_task_result)
elif api_task.api_send_enterprise_wechat == 2 or 0:
pass
def run_tasks(self):
logger.info("创建API线程任务...")
sleep(2)
threads = []
t1 = threading.Thread(target=self.run_cases)
threads.append(t1)
for t in threads:
t.start()
for t in threads:
t.join()
def run(self):
threads = []
t = threading.Thread(target=self.run_tasks)
threads.append(t)
for t in threads:
t.start()
if __name__ == '__main__':
logger.info("开始")
# run() # 丢给线程去运行任务
TaskThread(16).run()
logger.info("结束")
# -*- coding: utf-8 -*-
# @Time : 2021/4/20 14:04
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# import django
#
# django.setup()
# from automated_main.view.api_automation.api_test_task.api_test_task_view import scheduler
#
# __all__ = ('scheduler',)
# -*- coding: utf-8 -*-
# @Time : 2021/4/20 14:05
# @Author : wangyinghao
# @FileName: api_test_task_list_view.py
# @Software: PyCharm
"""
8.19 弃用
"""
# from django.views.generic import View
# from automated_main.utils.http_format import response_success
# from automated_main.models.api_automation.api_test_task import APITestTask
# import arrow
# class ApiTestTaskListView(View):
#
# def get(self, request, api_project_id, *args, **kwargs):
# """
# 代表获取所有API测试任务
# :param request:
# :param api_project_id: API项目id
# :param args:
# :param kwargs:
# :return:
# """
# status = None
# api_task = APITestTask.objects.filter(api_project_id=api_project_id).order_by('-id')
# api_task_list = []
# for api_tasks in api_task:
# if api_tasks.status == 0:
# status = "未执行"
# elif api_tasks.status == 1:
# status = "执行中"
# elif api_tasks.status == 2:
# status = "已完成"
# api_task_dict = {
# "id": api_tasks.id,
# "api_project_name": api_tasks.api_project.api_project_name,
# "api_test_task_name": api_tasks.api_test_task_name,
# "describe": api_tasks.describe,
# "cases": api_tasks.cases,
# "ui_project_name": api_tasks.api_project.api_project_name,
# "api_send_email": api_tasks.api_send_email,
# "api_send_enterprise_wechat": api_tasks.api_send_enterprise_wechat,
# "api_environment_id": api_tasks.api_environment_id,
# "database_id": api_tasks.database_id,
# "timing_task_status": api_tasks.timing_task_status,
# "time_interval_seconds": api_tasks.time_interval_seconds,
# "time_interval_hours": api_tasks.time_interval_hours,
# "time_interval_minutes": api_tasks.time_interval_minutes,
# "time_interval_day": api_tasks.time_interval_day,
# "end_time": api_tasks.end_time,
# "starting_time": api_tasks.starting_time,
# "status": status,
# "update_time": arrow.get(str(api_tasks.update_time)).format('YYYY-MM-DD HH:mm:ss'),
# "create_time": arrow.get(str(api_tasks.create_time)).format('YYYY-MM-DD HH:mm:ss'),
#
# }
# api_task_list.append(api_task_dict)
#
# return response_success(api_task_list)
# # -*- coding: utf-8 -*-
# # @Time : 2021/4/20 14:05
# # @Author :
# # @FileName: api_test_task_view.py
# # @Software: PyCharm
# from django.views.generic import View
# import json
# from django.forms import model_to_dict
# from automated_main.utils.http_format import response_success, response_failed
# from automated_main.exception.my_exception import MyException
# # from automated_main.models.api_automation.api_test_task import APITestTask, APITestResult, APITestResultAssociated
# # from automated_main.models.api_automation.api_project import APIProject
# # from automated_main.models.api_automation.api_business_test import ApiBusinessTest
# from automated_main.form.api_test_task import ApiTestTaskForm
# from automated_main.view.api_automation.api_test_task.extend.new_task_thread import TaskThread
# from django.core.paginator import Paginator
# from apscheduler.schedulers.background import BackgroundScheduler
# from apscheduler.jobstores.base import ConflictingIdError
# from django.core.exceptions import ObjectDoesNotExist
# import arrow
# import logging
#
# logger = logging.getLogger('django')
#
#
# class APITestTaskSuspended(View):
#
# def post(self, request, *args, **kwargs):
# """
# 暂停API任务
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
# api_task = APITestTask.objects.get(id=data["api_test_task_id"])
# api_task.status = 2
# api_task.save()
#
# return response_success("暂停API任务成功")
#
#
# class ApiTestTaskView(View):
#
# def get(self, request, api_test_task_id, *args, **kwargs):
# """
# 获取单个API任务
# :param request:
# :param api_test_task_id: API任务ID
# :param args:
# :param kwargs:
# :return:
# """
# api_test_task = APITestTask.objects.get(id=api_test_task_id)
# return response_success(model_to_dict(api_test_task))
#
# def delete(self, request, api_test_task_id, *args, **kwargs):
# """
# 删除API任务
# :param request:
# :param api_test_task_id:任务ID
# :param args:
# :param kwargs:
# :return:
# """
# # 移除原来的任务
# # remove_task(str(api_test_task_id))
# # logger.info(scheduler.get_jobs())
# APITestTask.objects.get(id=api_test_task_id).delete()
#
# return response_success("删除API任务成功")
#
# def put(self, request, *args, **kwargs):
# """
# 创建API测试任务
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
#
# form = ApiTestTaskForm(data)
# if form.is_valid():
# if data['api_test_task_id'] == 0:
# APITestTask.objects.create(**form.cleaned_data)
# # # 如果任务状态为False那么就暂停
# # if api_task.timing_task_status == "false":
# # run_timing_task(api_task.id)
# # pause_task(api_task.id)
# # logger.info(scheduler.get_jobs())
# # return response_success("创建API测试任务成功")
# # else:
# # # 然后开启修改后的任务
# # run_timing_task(str(api_task.id))
# # logger.info(scheduler.get_jobs())
# return response_success("创建API测试任务成功")
# # else:
# # return response_success("创建API测试任务失败")
# else:
# raise MyException()
#
# def post(self, request, api_test_task_id, *args, **kwargs):
# """
# 更改UI测试任务
# :param request:
# :param api_test_task_id: API测试任务ID
# :param args:
# :param kwargs:
# :return:
# """
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
# form = ApiTestTaskForm(data)
# if form.is_valid():
# api_task = APITestTask.objects.get(id=api_test_task_id)
# api_task.api_test_task_name = data['api_test_task_name']
# api_task.describe = data['describe']
# api_task.cases = data['cases']
# api_task.api_project_id = data['api_project_id']
# api_task.api_send_email = data['api_send_email']
# api_task.api_send_enterprise_wechat = data['api_send_enterprise_wechat']
# api_task.api_environment_id = data['api_environment_id']
# api_task.database_id = data['database_id']
# api_task.time_interval_seconds = data['time_interval_seconds']
# api_task.time_interval_hours = data['time_interval_hours']
# api_task.time_interval_minutes = data['time_interval_minutes']
# api_task.time_interval_day = data['time_interval_day']
# api_task.end_time = data['end_time']
# api_task.starting_time = data['starting_time']
# api_task.timing_task_status = data['timing_task_status']
# api_task.save()
#
# # logger.info(scheduler.get_jobs())
#
# # # 移除原来的任务
# # remove_task(api_task.id)
# # # 然后开启修改后的任务
# # run_timing_task(api_task.id)
# # 如果任务状态为False那么就暂停
# # if api_task.timing_task_status == "false":
# # remove_task(api_task.id)
# # run_timing_task(api_task.id)
# # pause_task(api_task.id)
# # else:
# # # 移除原来的任务
# # remove_task(api_task.id)
# # # 然后开启修改后的任务
# # run_timing_task(api_task.id)
#
# return response_success("编辑API测试任务成功")
# else:
# raise MyException()
#
#
# class GetApiCaseTree(View):
#
# def get(self, request, api_project_id, *args, **kwargs):
# """
# 获取Api测试用例树形结构
# :param request:
# :param api_project_id:
# :param args:
# :param kwargs:
# :return:
# """
# api_projects = APIProject.objects.filter(id=api_project_id)
# data_list = []
# for api_project in api_projects:
# api_project_dict = {
# "api_project_name": api_project.api_project_name,
# "isParent": True
# }
# api_case_list = []
# api_test_case = ApiBusinessTest.objects.filter(api_project_id=api_project.id)
# for api_test_cases in api_test_case:
# api_case_dict = {
# "api_test_case_name": api_test_cases.api_business_test_name,
# "isParent": False,
# "api_test_cases_id": api_test_cases.id
# }
# api_case_list.append(api_case_dict)
#
# api_project_dict["children"] = api_case_list
# data_list.append(api_project_dict)
# return response_success(data_list)
#
# def post(self, request, api_test_task_id, *args, **kwargs):
# """
# 修改API用例树形结构
# :param request:
# :param api_test_task_id: api任务id
# :param args:
# :param kwargs:
# :return:
# """
#
# if api_test_task_id == "":
# return MyException("任务id不能为空")
# api_test_task = APITestTask.objects.get(id=api_test_task_id)
# api_case_list_data = json.loads(api_test_task.cases)
# api_task_data = {
# "api_test_task_name": api_test_task.api_test_task_name,
# "describe": api_test_task.describe
# }
# api_projects = APIProject.objects.all()
# data_list = []
# for api_project in api_projects:
# api_project_dict = {
# "api_project_name": api_project.api_project_name,
# "isParent": True
# }
# ui_case_list = []
# api_test_cases = ApiBusinessTest.objects.filter(api_project_id=api_project.id)
# for api_test_case in api_test_cases:
# if api_test_case.id in api_case_list_data:
# ui_case_dict = {
# "api_test_case_name": api_test_case.ui_test_case_name,
# "api_test_case_id": api_test_case.id,
# "isParent": False,
# "checked": True,
# }
# else:
# ui_case_dict = {
# "api_test_case_name": api_test_case.ui_test_case_name,
# "api_test_case_id": api_test_case.id,
# "isParent": False,
# "checked": False,
# }
# ui_case_list.append(ui_case_dict)
#
# api_project_dict["children"] = ui_case_list
# data_list.append(api_project_dict)
# api_task_data["cases"] = data_list
# return response_success(api_task_data)
#
#
# class CheckApiResultList(View):
#
# def get(self, request, api_test_task_id, size_page, page, *args, **kwargs):
# """
# 查看API测试报告列表
# :param page:
# :param size_page:
# :param request:
# :param api_test_task_id:
# :param args:
# :param kwargs:
# :return:
# """
# if api_test_task_id == "":
# return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
# r = APITestResult.objects.filter(api_task_id=api_test_task_id).order_by('-create_time')
# data = []
# for i in r:
# result = {
# "id": i.id,
# "api_test_result_name": i.api_test_result_name,
# "create_time": i.create_time,
# "api_error_total_number": i.api_error_total_number,
# "api_successful_total_number": i.api_successful_total_number,
# "api_total_number": i.api_total_number
#
# }
# data.append(result)
# api_result_total = len(data)
# p = Paginator(data, size_page)
#
# if int(page) > int(p.num_pages):
# page1 = p.page(p.num_pages)
# current_page = page1.object_list
# else:
# page1 = p.page(page)
# current_page = page1.object_list
# return response_success({'status': 10102, 'data': current_page, 'api_result_total': api_result_total})
#
#
# class CheckApiResult(View):
# def get(self, request, api_test_result_id, size_page, page, *args, **kwargs):
# """
# 查看任务--测试报告列表--测试结果列表
# :param size_page: 展示条数
# :param page: 页数
# :param request:
# :param api_test_result_id:
# :param args:
# :param kwargs:
# :return:
# """
# if api_test_result_id == "":
# return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
# r = APITestResultAssociated.objects.filter(api_result_id=api_test_result_id)
#
# data = []
# for i in r:
# result = {
# "id": i.id,
# "api_test_case_name": i.api_test_case_name,
# "api_task_name": i.api_task.api_test_task_name,
# "api_business_test_name": i.api_business_test_name,
# "api_error": i.api_error,
# "api_successful": i.api_successful,
# "abnormal": i.abnormal,
# "json_extract_variable_conversion": i.json_extract_variable_conversion,
# "api_assertion_results": i.api_assertion_results,
# "api_request_results": i.api_request_results,
# "api_result_id": i.api_result_id,
# "api_task_id": i.api_task_id,
# "create_time": arrow.get(str(i.create_time)).format('YYYY-MM-DD HH:mm:ss'),
# }
# data.append(result)
# p = Paginator(data, size_page)
# if int(page) > int(p.num_pages):
# page1 = p.page(p.num_pages)
# current_page = page1.object_list
# else:
# page1 = p.page(page)
# current_page = page1.object_list
#
# api_result = APITestResult.objects.get(id=api_test_result_id)
#
# case_result_total = [int(api_result.api_successful_total_number), int(api_result.api_error_total_number)]
#
# return response_success({'status': 10102, 'data': current_page, "case_result_total": case_result_total})
#
# def post(self, request, api_test_case_result_id, *args, **kwargs):
# """
# 查看任务--测试报告列表--测试结果列表--单独测试用例报告
# :param request:
# :param api_test_case_result_id:API测试结果关联表的ID
# :param args:
# :param kwargs:
# :return:
# """
# if api_test_case_result_id == "":
# return response_failed({"status": 10102, "message": "api_test_case_result_id不能为空"})
# r = APITestResultAssociated.objects.filter(id=api_test_case_result_id)
# data = []
# for i in r:
# result = {
# "id": i.id,
# "api_test_case_name": i.api_test_case_name,
# "api_task_name": i.api_task.api_test_task_name,
# "api_business_test_name": i.api_business_test_name,
# "api_error": i.api_error,
# "api_successful": i.api_successful,
# "abnormal": i.abnormal,
# "json_extract_variable_conversion": i.json_extract_variable_conversion,
# "api_assertion_results": i.api_assertion_results,
# "api_request_results": i.api_request_results,
# "api_result_id": i.api_result_id,
# "api_task_id": i.api_task_id,
# "create_time": i.create_time,
# "api_variable_results": i.api_variable_results,
# "api_header": i.api_header,
# "api_url": i.api_url,
# "api_body": i.api_body
# }
#
# data.append(result)
# return response_success({'status': 10102, 'data': data})
#
# def delete(self, request, api_test_result_id, *args, **kwargs):
# """
# 查看任务--测试报告列表--删除测试报告
# :param request:
# :param api_test_result_id:API测试结果关联表的ID
# :param args:
# :param kwargs:
# :return:
# """
# if api_test_result_id == "":
# return response_failed({"status": 10102, "message": "api_test_result_id不能为空"})
# APITestResult.objects.get(id=api_test_result_id).delete()
#
# return response_success("删除测试报告成功")
#
#
# class CheckApiResultErrorList(View):
# def get(self, request, api_test_result_id, size_page, page, *args, **kwargs):
# """
# 查看任务--测试报告列表--测试结果列表
# :param size_page: 展示条数
# :param page: 页数
# :param request:
# :param api_test_result_id:
# :param args:
# :param kwargs:
# :return:
# """
# if api_test_result_id == "":
# return response_failed({"status": 10102, "message": "api_test_task_id不能为空"})
# r = APITestResultAssociated.objects.filter(api_result_id=api_test_result_id, api_error=1)
# data = []
# for i in r:
# result = {
# "id": i.id,
# "api_test_case_name": i.api_test_case_name,
# "api_task_name": i.api_task.api_test_task_name,
# "api_business_test_name": i.api_business_test_name,
# "api_error": i.api_error,
# "api_successful": i.api_successful,
# "abnormal": i.abnormal,
# "json_extract_variable_conversion": i.json_extract_variable_conversion,
# "api_assertion_results": i.api_assertion_results,
# "api_request_results": i.api_request_results,
# "api_result_id": i.api_result_id,
# "api_task_id": i.api_task_id,
# "create_time": arrow.get(str(i.create_time)).format('YYYY-MM-DD HH:mm:ss')
# }
# data.append(result)
# p = Paginator(data, size_page)
#
# if int(page) > int(p.num_pages):
# page1 = p.page(p.num_pages)
# current_page = page1.object_list
# else:
# page1 = p.page(page)
# current_page = page1.object_list
# api_result = APITestResult.objects.get(id=api_test_result_id)
#
# case_result_total = [int(api_result.api_successful_total_number), int(api_result.api_error_total_number)]
# return response_success({'status': 10102, 'data': current_page, "case_result_total": case_result_total})
#
#
# class PerformApiTask(View):
#
# def post(self, request, api_test_task_id, *args, **kwargs):
# """
# 执行当前API任务
# :param request:
# :param api_test_task_id:
# :param args:
# :param kwargs:
# :return:
# """
#
# if api_test_task_id == "":
# return response_failed({"status": 10200, "message": "api_test_task_id is null"})
#
# # 1.在执行线程之前,判断当前任务是否在执行
# api_tasks = APITestTask.objects.get(id=api_test_task_id)
# if api_tasks.status == 1:
# return response_failed({"status": 10200, "message": "当前该任务正在执行!"})
# else:
# # 2. 修改任务的状态为:1-执行中
# api_tasks = APITestTask.objects.get(id=api_test_task_id)
# api_tasks.status = 1
# api_tasks.save()
# # 通过多线程运行测试任务
# TaskThread(api_test_task_id).run()
# return response_success({"status": 10200, "message": "任务开始执行!"})
#
# def get(self, request, *args, **kwargs):
# """
# 执行所有API任务
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
# api_test_task = APITestTask.objects.filter(timing_task_status="true")
# for tasks in api_test_task:
#
# # 1.在执行线程之前,判断当前有没有任务在执行
# api_tasks = APITestTask.objects.get(id=tasks.id)
# if api_tasks.status == 1:
# logger.info("该任务正在执行中:" + tasks.api_test_task_name)
# continue
# else:
# # 2. 修改任务的状态为:1-执行中
# api_tasks = APITestTask.objects.get(id=tasks.id)
# api_tasks.status = 1
# api_tasks.save()
# # 通过多线程运行测试任务
# TaskThread(tasks.id).run()
# return response_success({"status": 10200, "message": "任务开始执行!"})
#
#
# class ApiServiceChangesTask(View):
#
# def post(self, request, *args, **kwargs):
# """
# 获取YaPi项目名称
# :param request:
# :param args:
# :param kwargs:
# :return:
# """
# body = request.body
# if not body:
# return response_success()
# data = json.loads(body)
# for ser in data['service']:
# # 1.在执行线程之前,判断当前任务是否在执行
# api_tasks = APITestTask.objects.get(api_test_task_name=ser)
# if api_tasks.status == 1:
# return response_failed({"status": 10200, "message": "当前该任务正在执行!"})
# else:
# # 2. 修改任务的状态为:1-执行中
# api_tasks = APITestTask.objects.get(api_test_task_name=ser)
# api_tasks.status = 1
# api_tasks.save()
# # 通过多线程运行测试任务
# TaskThread(api_tasks.id).run()
#
# return response_success()
#
# # def task_func(task_id):
# # api_task = APITestTask.objects.get(id=task_id)
# # api_task.status = 1
# # api_task.save()
# # TaskThread(task_id).run()
# #
# #
# # # 添加任务
# # def add_task(id, func, starting_time, end_time, days, hours, minutes, second, scheduler, kwargs):
# # """添加一个定时任务"""
# # """
# # id: 任务id
# # func: 执行的方法
# # from_date: 起始时间
# # interval_time: 间隔时间
# # scheduler: 执行器 scheduler = BackgroundScheduler()
# # kwargs: 方法需要的参数dict
# # """
# # if len(starting_time) != 0 or len(end_time) != 0:
# # pass
# # else:
# # starting_time, end_time = None, None
# # scheduler.add_job(func, 'interval', start_date=starting_time, end_date=end_time,
# # days=days, hours=hours, minutes=minutes,
# # seconds=second, id=id, replace_existing=True, kwargs=kwargs)
# #
# #
# # # 暂停任务
# # def pause_task(task_id):
# # """暂停任务"""
# # scheduler.pause_job(str(task_id))
# #
# #
# # # 恢复任务
# # def resume_task(task_id):
# # """恢复任务"""
# # scheduler.resume_job(str(task_id))
# #
# #
# # # 移除任务
# # def remove_task(task_id):
# # """移除任务
# # task_id:移除的任务id
# # """
# # scheduler.remove_job(str(task_id))
# #
# #
# # # 移除任务
# # def get_timing_task():
# # """获取任务
# # task_id:移除的任务id
# # """
# # scheduler.get_jobs()
# #
# #
# # # 执行任务
# # def run_timing_task(task_id):
# # """执行定时任务"""
# # try:
# # api_task = APITestTask.objects.filter(id=task_id).get()
# # add_task(str(api_task.id), task_func, api_task.starting_time, api_task.end_time,
# # api_task.time_interval_day, api_task.time_interval_hours, api_task.time_interval_minutes,
# # api_task.time_interval_seconds, scheduler, kwargs={"task_id": api_task.id})
# # except ConflictingIdError:
# # return response_success({"ok": "任务重复执行"})
# # except ObjectDoesNotExist:
# # return response_success({"ok": "任务id不存在"})
# #
# #
# # # 启动django时会把任务状态为True的任务,启动,为False的任务启动然后暂停
# # scheduler = BackgroundScheduler(timezone='Asia/Shanghai')
# # taskList = APITestTask.objects.filter(timing_task_status="true")
# # for task in taskList:
# # # 开启定时任务
# # run_timing_task(str(task.id))
# # logger.info("开启了定时任务" + str(task.id))
# # taskList = APITestTask.objects.filter(timing_task_status="false")
# # for task in taskList:
# # # 开启定时任务
# # logger.info("暂停定时任务" + str(task.id))
# # run_timing_task(str(task.id))
# # pause_task(str(task.id))
# # # scheduler.start()
# #
# # # scheduler.get_jobs()
# # logger.info(scheduler.get_jobs())
# #
# # import sys, socket
# #
# # try:
# # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# # sock.bind(("127.0.0.1", 47200))
# # except socket.error:
# # print("!!!scheduler already started, DO NOTHING")
# #
# # else:
# # scheduler.start()
# # scheduler.get_jobs()
# # logger.info(scheduler.get_jobs())
# # print("scheduler started")
\ No newline at end of file
# -*- coding: utf-8 -*-
# @Time : 2021/5/14 18:06
# @Author : wangyinghao
# @FileName: RequestHandler.py
# @Software: PyCharm
import requests
class RequestHandler:
def __init__(self):
"""session管理器"""
self.session = requests.session()
def visit(self, method, url, **kwargs):
return self.session.request(method=method, url=url, **kwargs)
def close_session(self):
"""关闭session"""
self.session.close()
if __name__ == '__main__':
# 以下是测试代码
# post请求接口
url = 'https://msg.csdn.net/v1/web/message/view/unread'
payload = {"coupon": "true"}
req = RequestHandler()
login_res = req.visit("post", url, params=payload)
print(login_res.text)
requests.request("post", url)
# -*- coding: utf-8 -*-
# @Time : 2020/7/15 15:22
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
# -*- coding: utf-8 -*-
# @Time : 2021/11/25 19:56
# @Author : wangyinghao
# @Site :
# @File : new_run_task.py
# @Software: PyCharm
import django
import json
import os
import re
import sys
from os.path import dirname, abspath
BASE_DIR = dirname(dirname(dirname(abspath(__file__))))
BASE_PATH = BASE_DIR.replace("\\", "/")
sys.path.append(BASE_PATH)
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
sys.path.extend(['/home/AutomatedTestPlatform'])
# project_name 项目名称
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AutomatedTestPlatform.settings")
django.setup()
from automated_main.models.api_automation.api_test_case import ApiParameterExtraction
from automated_main.models.api_automation.api_test_task import APITestResultAssociated
from automated_main.models.api_automation.api_environment import APIGlobalVariable
from automated_main.utils.handle_db import HandleDB
from automated_main.models.api_automation.api_database import APIDatabase
from automated_main.utils.api_utils import ExtractParameters
from automated_main.utils.api_utils import RegularMatch
from automated_main.utils.api_utils import InterfaceRequest
import logging
import ast
logger = logging.getLogger('django')
logger.info("运行测试文件:" + BASE_PATH)
# 定义扩展的目录
EXTEND_DIR = BASE_PATH + "/api_test_task/extend/"
logger.info("地址信息" + EXTEND_DIR)
def new_test_run_cases(case_id):
for case in case_id:
api_test_case_id = (case['api_test_case_id'])
api_test_case_name = (case['api_test_case_name'])
api_url = (case['api_url'])
api_method = (case['api_method'])
api_parameter_types = (case['api_parameter_types'])
api_headers = (case['api_headers'])
api_parameter_body = (case['api_parameter_body'])
api_assert_type = (case['api_assert_type'])
api_parameter_extraction = (case['api_parameter_extraction'])
parameter_data = (case['parameter_data'])
api_assert_text = (case['api_assert_text'])
api_result_id = (case['api_result_id'])
api_task_id = (case['api_task_id'])
database_id = (case['dataBase_id'])
database_sql = (case['database_sql'])
api_business_test_name = (case['api_business_test_name'])
api_environment_id = (case['api_environment_id'])
api_assertion_results = ""
api_error = ""
api_successful = ""
api_variable_results = ""
abnormal = ""
json_loads = ""
try:
api_url = RegularMatch(api_url, api_environment_id, "1")
if api_headers == "{}" or "":
header_dict = {}
else:
api_headers = RegularMatch(api_headers, api_environment_id, "1")
header = api_headers.replace("\'", "\"")
header_dict = json.loads(header)
if api_parameter_body == "{}" or "":
api_parameter_body_dict = {}
else:
api_parameter_body = RegularMatch(api_parameter_body, api_environment_id, "1")
api_parameter = api_parameter_body.replace("\'", "\"")
api_parameter_body_dict = json.loads(api_parameter)
if parameter_data == "{}" or "":
data_payload = {}
else:
parameter_data_task = RegularMatch(str(parameter_data), api_environment_id, "1")
data_payload = ast.literal_eval(parameter_data_task)
r = InterfaceRequest(str(api_method), str(api_parameter_types), api_url, header_dict,
api_parameter_body_dict, data_payload)
if r == "请求超时":
api_error = 1
api_successful = 0
APITestResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results={"results": "请求超时,断言失败"},
api_variable_results={"results": "请求超时无法提取变量"},
api_request_results={"results": "请求超时"},
api_result_id=api_result_id,
api_task_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=api_url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
else:
if api_assert_type == '':
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
elif api_assert_type == 1:
try:
r_text = re.sub(r'(\\u[\s\S]{4})',
lambda x: x.group(1).encode("utf-8").decode("unicode-escape"), r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(api_assert_text.split())
assert r_text_data in r_text_test
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error(
"断言失败,用例名称是:" + api_test_case_name + "断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text) + str(e))
api_assertion_results = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (api_assert_text, r_text)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 2:
r_text = re.sub(r'(\\u[\s\S]{4})', lambda x: x.group(1).encode("utf-8").decode("unicode-escape"),
r.text)
r_text_test = "".join(r_text.split())
r_text_data = "".join(api_assert_text.split())
try:
assert r_text_data == r_text_test
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error(
"断言失败,用例名称是:" + api_test_case_name + "断言内容 %s 与响应结果不匹配,%s" % (
api_assert_text, r_text) + str(e))
api_assertion_results = "断言失败: 断言内容 %s 与响应结果不匹配,%s" % (api_assert_text, r_text)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 3:
database = APIDatabase.objects.get(id=database_id)
db = HandleDB(database.api_host, int(database.api_port), database.user, database.password,
database.database)
count = db.get_count(database_sql)
db.close()
if str(count) == str(api_assert_text):
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
else:
logger.error("断言失败,用例名称是:" + api_test_case_name + '断言失败,查询的数据是: %s' % str(count))
api_assertion_results = '断言失败,查询的数据是: %s' % str(count)
api_error = 1
api_successful = 0
pass
elif api_assert_type == 4:
try:
assert str(api_assert_text) == str(r.status_code)
api_error = 0
api_successful = 1
api_assertion_results = "断言成功"
except Exception as e:
logger.error("断言失败,用例名称是:" + api_test_case_name + "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (
api_assert_text, str(r.status_code)) + str(e))
api_assertion_results = "断言失败: code状态码 %s 与响应状态码不匹配,%s" % (api_assert_text, str(r.status_code))
api_error = 1
api_successful = 0
pass
try:
response_message = r.json()
except json.decoder.JSONDecodeError:
api_error = 1
api_successful = 0
APITestResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results="",
api_request_results={"result": "接口返回结果类型错误非JSON格式"},
api_result_id=api_result_id,
api_task_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=api_url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
continue
if ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).count() > 0:
ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id).delete()
for api_parameter_extractions in api_parameter_extraction:
if api_parameter_extractions['api_value_variable'] == "":
pass
else:
v_text = api_parameter_extractions['api_value_variable'].split(".")
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
json_loads = "提取变量json.loads(r.text) 失败:" + str(e)
logger.error("提取变量json.loads(r.text) 失败:" + str(e))
pass
try:
for a in v_text:
if "[" in a and "]" in a:
variable_1 = a.split('[')[0]
variable_2 = a.split('[')[1].split(']')[0]
if variable_1 == "":
api_result = api_result[0]
else:
api_result = api_result[variable_1][int(variable_2)]
else:
if a == "0":
api_result = api_result[int(a)]
else:
api_result = api_result[a]
api_variable_results = str(api_result)
except Exception as e:
api_variable_results = api_parameter_extractions['api_key_variable']
pass
ApiParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_variable_results,
api_value_variable=api_parameter_extractions[
'api_value_variable'],
api_key_variable=api_parameter_extractions[
'api_key_variable'])
else:
for api_parameter_extractions in api_parameter_extraction:
if api_parameter_extractions['api_key_variable'] == "":
pass
else:
v_text = api_parameter_extractions['api_value_variable'].split(".")
# 提取变量
try:
api_result = json.loads(r.text)
except Exception as e:
json_loads = "提取变量json.loads(r.text) 失败:" + str(e)
logger.error("提取变量json.loads(r.text) 失败:" + str(e))
pass
try:
for a in v_text:
if "[" in a and "]" in a:
variable_1 = a.split('[')[0]
variable_2 = a.split('[')[1].split(']')[0]
api_result = api_result[variable_1][int(variable_2)]
else:
api_result = api_result[a]
api_variable_results = str(api_result)
except Exception as e:
logger.info(str(api_test_case_name) + " 参数提取失败" + api_parameter_extractions[
'api_key_variable'] + str(e))
api_variable_results = api_parameter_extractions['api_key_variable']
logger.error(api_variable_results)
pass
if ApiParameterExtraction.objects.filter(
api_key_variable=api_parameter_extractions['api_key_variable']).count() > 0:
api_parameter_extraction_list = (
str(api_parameter_extractions['api_key_variable']) + "变量名称重复,请重新填写")
else:
ApiParameterExtraction.objects.create(api_test_case_id=api_test_case_id,
api_variable_results=api_parameter_extractions[
'api_variable_results'],
api_value_variable=api_variable_results,
api_key_variable=api_parameter_extractions[
'api_key_variable'])
api_parameter_extraction = ApiParameterExtraction.objects.filter(api_test_case_id=api_test_case_id)
api_parameter_extraction_list = []
if api_parameter_extraction.count() > 0:
for api_parameter_extractions in api_parameter_extraction:
api_parameter_extraction_dict = {
"api_key_variable": api_parameter_extractions.api_key_variable,
"api_variable_results": api_parameter_extractions.api_variable_results
}
api_parameter_extraction_list.append(api_parameter_extraction_dict)
APITestResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=r.json(),
api_result_id=api_result_id,
api_task_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=r.url,
api_body=api_parameter_body_dict,
api_header=header_dict
)
except Exception as e:
abnormal = str(e)
if api_assertion_results == "断言成功":
api_error = 0
api_successful = 1
APITestResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=r.text.encode().decode("unicode_escape"),
api_result_id=api_result_id,
api_task_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=r.url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
else:
try:
result = r.json()
except Exception as e:
result = r.text
pass
api_error = 1
api_successful = 0
APITestResultAssociated.objects.create(api_test_case_name=api_test_case_name, api_error=api_error,
api_successful=api_successful, abnormal=abnormal,
json_extract_variable_conversion=json_loads,
api_assertion_results=api_assertion_results,
api_variable_results=str(api_parameter_extraction_list),
api_request_results=result,
api_result_id=api_result_id,
api_task_id=api_task_id,
api_business_test_name=api_business_test_name,
api_url=api_url,
api_header=header_dict,
api_body=api_parameter_body_dict,
)
continue
# # -*- coding: utf-8 -*-
# # @Time : 2021/11/23 11:21
# # @Author : wangyinghao
# # @Site :
# # @File : new_task_thread.py
# # @Software: PyCharm
# import os
# import json
# import threading
# import django
#
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AutomatedTestPlatform.settings")
# django.setup()
# from time import sleep
# from automated_main.models.api_automation.api_business_test import ApiBusinessTest, ApiBusinessTestAssociated
# from automated_main.models.api_automation.api_test_task import APITestTask
# from automated_main.models.api_automation.api_test_task import APITestResult
# from automated_main.models.api_automation.api_test_case import ApiTestCase, ApiParameterExtraction, ApiParameterData
# from automated_main.models.api_automation.api_test_task import APITestResultAssociated
# from automated_main.utils.send_email import SendEmail
# from automated_main.utils.send_enterprise_wechat import SendEnterpriseWechatMsg
# from AutomatedTestPlatform import settings
# from automated_main.view.api_automation.api_test_task.extend.new_run_task import new_test_run_cases
# import time
# import logging
#
# BASE_PATH = settings.BASE_DIR.replace("\\", "/")
# EXTEND_DIR = BASE_PATH + "/automated_main/view/api_automation/api_test_task/extend/"
# # EXTEND_DIR = BASE_PATH + "\\automated_main\\view\\api_automation\\api_test_task\\extend\\"
# logger = logging.getLogger('django')
#
#
# class TaskThread:
#
# def __init__(self, task_id):
# self.tid = task_id
#
# def run_cases(self):
# logger.info("运行某一个任务下面的所有测试用例")
#
# api_task = APITestTask.objects.get(id=self.tid)
# # 1. 拿到任务对应用例的列表
# api_case_list = json.loads(api_task.cases)
#
# logger.info("拿到任务对应用例的列表" + api_task.cases)
# now = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))
# api_result = APITestResult.objects.create(
# api_task_id=self.tid,
# api_test_result_name=now,
# api_environment_id=api_task.api_environment.id
# )
# api_result_id = api_result.id
# # 2. 获取API用例数据
# for cid in api_case_list:
# logger.info(cid)
# api_business_test = ApiBusinessTest.objects.get(id=cid)
# api_associated = ApiBusinessTestAssociated.objects.filter(bid_id=cid)
# data_list = []
# for api_associates in api_associated:
# api_test_case = ApiTestCase.objects.get(id=api_associates.api_test_case_id)
# api_parameter_extraction = ApiParameterExtraction.objects.filter(
# api_test_case_id=api_associates.api_test_case_id)
#
# parameter_data = ApiParameterData.objects.filter(api_test_case_id=api_associates.api_test_case_id)
#
# api_parameter_extraction_list = []
# api_parameter_dict = {}
#
# for api_parameters in parameter_data:
# if api_parameters.api_must_parameter == "true":
# api_parameter_dict.update(
# {api_parameters.api_parameter_name: api_parameters.api_parameter_value})
# else:
# pass
# for api_parameter_extractions in api_parameter_extraction:
# api_parameter_extraction_dict = {
# "api_value_variable": api_parameter_extractions.api_value_variable,
# "api_key_variable": api_parameter_extractions.api_key_variable,
# "api_variable_results": api_parameter_extractions.api_variable_results,
#
# }
# api_parameter_extraction_list.append(api_parameter_extraction_dict)
#
# api_associated_dict = {
# "api_business_test_name": api_business_test.api_business_test_name,
# "api_result_id": api_result.id,
# "api_task_id": self.tid,
# "api_test_case_id": api_associates.api_test_case_id,
# "api_test_case_name": api_test_case.api_test_case_name,
# "api_method": api_test_case.api_method,
# "dataBase_id": api_task.database_id,
# "database_sql": api_test_case.database_sql,
# "api_url": api_task.api_environment.api_title + api_test_case.api_url,
# "api_parameter_types": api_test_case.api_parameter_types,
# "api_headers": api_test_case.api_headers,
# "parameter_data": api_parameter_dict,
# "api_parameter_body": api_test_case.api_parameter_body,
# "api_assert_type": api_test_case.api_assert_type,
# "api_assert_text": api_test_case.api_assert_text,
# "api_parameter_extraction": api_parameter_extraction_list,
# "api_environment_id": api_task.api_environment.id,
# "case_steps": int(api_associates.case_steps)
# }
# data_list.append(api_associated_dict)
#
# data_list_sorting = sorted(data_list, key=lambda x: x['case_steps'])
# # 3.这里就可以获取到业务测试用例 data_list_sorting 赋值到 new_test_run_cases中
# new_test_run_cases(data_list_sorting)
#
# logger.info(api_result.id)
# api_total_number = APITestResultAssociated.objects.filter(api_result_id=api_result.id).count()
# api_error_total_number = APITestResultAssociated.objects.filter(api_result_id=api_result.id,
# api_error=1).count()
# api_successful_total_number = APITestResultAssociated.objects.filter(api_result_id=api_result.id,
# api_successful=1).count()
# api_test_result = APITestResult.objects.get(id=api_result.id)
# api_test_result.api_error_total_number = api_error_total_number
# api_test_result.api_successful_total_number = api_successful_total_number
# api_test_result.api_total_number = api_total_number
# api_test_result.save()
# # 4. 修改任务的状态,执行完成
# # task = APITestTask.objects.get(id=self.tid)
# api_task.status = 2
# api_task.save()
#
# # 取小数后2位,通过率
# pass_result = "%.2f%%" % (api_successful_total_number / api_total_number * 100)
# fail_result = "%.2f%%" % (api_error_total_number / api_total_number * 100)
# user_list = api_task.api_send_email
# sub = "接口自动化测试报告-%s" % api_task.api_test_task_name
#
# api_result = APITestResultAssociated.objects.filter(api_result_id=api_result.id, api_error=1)
# content = "这次一共测试%s个接口,通过个数为%s,失败个数为%s,通过率为%s,失败率为%s \n" % (
# api_total_number, api_successful_total_number, api_error_total_number, pass_result, fail_result)
# error_case = ""
# for a in api_result:
# case_result = "业务测试用例名称:" + a.api_business_test_name + ", 测试用例名称:" + a.api_test_case_name + \
# ", 断言结果:" + a.api_assertion_results
#
# error_case += case_result + ",\n"
#
# # 5.发送邮件
# if api_task.api_send_email == "" or None:
# logger.info("该任务无需发送邮件,未填写邮箱")
# else:
# sen = SendEmail()
# sen.send_mail(user_list, sub, content + error_case)
#
# # 6 发送企业微信
# if api_error_total_number > 0:
# if api_task.api_send_enterprise_wechat == 1:
# ENV_PROFILE = os.getenv("ENV")
# if ENV_PROFILE == "SERVER":
# result_host = 'http://qa.rd.com'
# elif ENV_PROFILE == "1":
# result_host = 'http://localhost:8080'
# api_task_result = result_host + "/#/api_test_task_result?apiResultId=" + str(api_result_id)
# # wx_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=a6f1ce13-2d16-465d-b03e-791fae0f3562"
# wx_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b3cd3bec-3f69-484b-bd6a-a65016ca9f54"
# a = SendEnterpriseWechatMsg()
# a.send_msg(wx_url, api_total_number, pass_result, api_successful_total_number, api_error_total_number,
# api_task_result)
#
# elif api_task.api_send_enterprise_wechat == 2 or 0:
# pass
#
# def run_tasks(self):
# logger.info("创建API线程任务...")
# sleep(2)
# threads = []
# t1 = threading.Thread(target=self.run_cases)
# threads.append(t1)
#
# for t in threads:
# t.start()
#
# for t in threads:
# t.join()
#
# def run(self):
# threads = []
# t = threading.Thread(target=self.run_tasks)
# threads.append(t)
#
# for t in threads:
# t.start()
#
#
# if __name__ == '__main__':
# logger.info("开始")
# # run() # 丢给线程去运行任务
# TaskThread(16).run()
# logger.info("结束")
# FileName : MyHTMLTestRunner.py
# Author : wangyinghao
# DateTime : 2019/1/9 21:04
# SoftWare : PyCharm
import datetime
import io
import unittest
from xml.sax import saxutils
import sys
"""
A TestRunner for use with the Python unit testing framework. It
generates a HTML report to show the result at a glance.
The simplest way to use this is to invoke its main method. E.g.
import unittest
import HTMLTestRunner
... define your tests ...
if __name__ == '__main__':
HTMLTestRunner.main()
For more customization options, instantiates a HTMLTestRunner object.
HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.
# output to a file
fp = file('my_report.html', 'wb')
runner = HTMLTestRunner.HTMLTestRunner(
stream=fp,
title='My unit test',
description='This demonstrates the report output by HTMLTestRunner.'
)
# Use an external stylesheet.
# See the Template_mixin class for more customizable options
runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'
# run the test
runner.run(my_test_suite)
------------------------------------------------------------------------
Copyright (c) 2004-2007, Wai Yip Tung
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name Wai Yip Tung nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
# URL: http://tungwaiyip.info/software/HTMLTestRunner.html
__author__ = "Wai Yip Tung, Findyou,Adil"
__version__ = "0.8.2.3"
"""
Change History
Version 0.8.2.1 -Findyou
* 改为支持python3
Version 0.8.2.1 -Findyou
* 支持中文,汉化
* 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js)
* 增加 通过分类显示、测试人员、通过率的展示
* 优化“详细”与“收起”状态的变换
* 增加返回顶部的锚点
Version 0.8.2
* Show output inline instead of popup window (Viorel Lupu).
Version in 0.8.1
* Validated XHTML (Wolfgang Borgert).
* Added description of test classes and test cases.
Version in 0.8.0
* Define Template_mixin class for customization.
* Workaround a IE 6 bug that it does not treat <script> block as CDATA.
Version in 0.7.1
* Back port to Python 2.3 (Frank Horowitz).
* Fix missing scroll bars in detail log (Podi).
"""
# TODO: color stderr
# TODO: simplify javascript using ,ore than 1 class in the class attribute?
# ------------------------------------------------------------------------
# The redirectors below are used to capture output during testing. Output
# sent to sys.stdout and sys.stderr are automatically captured. However
# in some cases sys.stdout is already cached before HTMLTestRunner is
# invoked (e.g. calling logging.basicConfig). In order to capture those
# output, use the redirectors for the cached stream.
#
# e.g.
# >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
# >>>
class OutputRedirector(object):
""" Wrapper to redirect stdout or stderr """
def __init__(self, fp):
self.fp = fp
def write(self, s):
self.fp.write(s)
def writelines(self, lines):
self.fp.writelines(lines)
def flush(self):
self.fp.flush()
stdout_redirector = OutputRedirector(sys.stdout)
stderr_redirector = OutputRedirector(sys.stderr)
# ----------------------------------------------------------------------
# Template
class Template_mixin(object):
"""
Define a HTML template for report customerization and generation.
Overall structure of an HTML report
HTML
+------------------------+
|<html> |
| <head> |
| |
| STYLESHEET |
| +----------------+ |
| | | |
| +----------------+ |
| |
| </head> |
| |
| <body> |
| |
| HEADING |
| +----------------+ |
| | | |
| +----------------+ |
| |
| REPORT |
| +----------------+ |
| | | |
| +----------------+ |
| |
| ENDING |
| +----------------+ |
| | | |
| +----------------+ |
| |
| </body> |
|</html> |
+------------------------+
"""
STATUS = {
0: '通过',
1: '失败',
2: '错误',
}
# 默认测试标题
DEFAULT_TITLE = '接口自动化测试报告'
DEFAULT_DESCRIPTION = ''
# 默认测试人员
DEFAULT_TESTER = 'QA'
# ------------------------------------------------------------------------
# HTML Template
HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>%(title)s</title>
<meta name="generator" content="%(generator)s"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcss.com/echarts/3.8.5/echarts.common.min.js"></script>
<!-- <script type="text/javascript" src="js/echarts.common.min.js"></script> -->
%(stylesheet)s
</head>
<body >
<script language="javascript" type="text/javascript">
output_list = Array();
/*level 调整增加只显示通过用例的分类 --Adil
0:Summary //all hiddenRow
1:Failed //pt hiddenRow, ft none
2:Pass //pt none, ft hiddenRow
3:Error // pt hiddenRow, ft none
4:All //pt none, ft none
下面设置 按钮展开逻辑 --Yang Yao Jun
*/
function showCase(level) {
trs = document.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++) {
tr = trs[i];
id = tr.id;
if (id.substr(0,2) == 'ft') {
if (level == 2 || level == 0 ) {
tr.className = 'hiddenRow';
}
else {
tr.className = '';
}
}
if (id.substr(0,2) == 'pt') {
if (level < 2 || level ==3 ) {
tr.className = 'hiddenRow';
}
else {
tr.className = '';
}
}
}
//加入【详细】切换文字变化 --Findyou
detail_class=document.getElementsByClassName('detail');
//console.log(detail_class.length)
if (level == 3) {
for (var i = 0; i < detail_class.length; i++){
detail_class[i].innerHTML="收起"
}
}
else{
for (var i = 0; i < detail_class.length; i++){
detail_class[i].innerHTML="详细"
}
}
}
function showClassDetail(cid, count) {
var id_list = Array(count);
var toHide = 1;
for (var i = 0; i < count; i++) {
//ID修改 点 为 下划线 -Findyou
tid0 = 't' + cid.substr(1) + '_' + (i+1);
tid = 'f' + tid0;
tr = document.getElementById(tid);
if (!tr) {
tid = 'p' + tid0;
tr = document.getElementById(tid);
}
id_list[i] = tid;
if (tr.className) {
toHide = 0;
}
}
for (var i = 0; i < count; i++) {
tid = id_list[i];
//修改点击无法收起的BUG,加入【详细】切换文字变化 --Findyou
if (toHide) {
document.getElementById(tid).className = 'hiddenRow';
document.getElementById(cid).innerText = "详细"
}
else {
document.getElementById(tid).className = '';
document.getElementById(cid).innerText = "收起"
}
}
}
function html_escape(s) {
s = s.replace(/&/g,'&');
s = s.replace(/</g,'<');
s = s.replace(/>/g,'>');
return s;
}
</script>
<div id="div_base">
%(heading)s
%(report)s
%(ending)s
%(chart_script)s
</body>
</html>
"""
# variables: (title, generator, stylesheet, heading, report, ending, chart_script)
# ------------------------------------------------------------------------
# Stylesheet
#
# alternatively use a <link> for external style sheet, e.g.
# <link rel="stylesheet" href="$url" type="text/css">
ECHARTS_SCRIPT = """
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('chart'));
// 指定图表的配置项和数据
var option = {
title : {
text: '测试执行情况',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%%)"
},
color: ['#95b75d', 'grey', '#b64645'],
legend: {
orient: 'vertical',
left: 'left',
data: ['通过','失败','错误']
},
series : [
{
name: '测试执行情况',
type: 'pie',
radius : '60%%',
center: ['50%%', '60%%'],
data:[
{value:%(Pass)s, name:'通过'},
{value:%(fail)s, name:'失败'},
{value:%(error)s, name:'错误'}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
""" # variables: (Pass, fail, error)
STYLESHEET_TMPL = """
<style type="text/css" media="screen">
body { font-family: Microsoft YaHei,Tahoma,arial,helvetica,sans-serif; font-size: 80%; }
table { font-size: 100%; }
pre { white-space: pre-wrap;word-wrap: break-word; }
/* -- heading ---------------------------------------------------------------------- */
h1 {
font-size: 16pt;
color: gray;
}
.heading {
margin-top: 0ex;
margin-bottom: 1ex;
}
.heading .attribute {
margin-top: 1ex;
margin-bottom: 0;
}
.heading .description {
margin-top: 2ex;
margin-bottom: 3ex;
}
/* -- css div popup ------------------------------------------------------------------------ */
a.popup_link {
}
a.popup_link:hover {
color: red;
}
.popup_window {
display: none;
position: relative;
left: 0px;
top: 0px;
/*border: solid #627173 1px; */
padding: 10px;
/* */
font-family: "Lucida Console", "Courier New", Courier, monospace;
text-align: left;
font-size: 8pt;
/* width: 500px;*/
}
/* -- report ------------------------------------------------------------------------ */
#total_row { font-weight: bold; }
.passCase { color: #5cb85c; }
.failCase { color: #d9534f; font-weight: bold; }
.errorCase { color: #f0ad4e; font-weight: bold; }
.hiddenRow { display: none; }
.testcase { margin-left: 2em; }
</style>
"""
# ------------------------------------------------------------------------
# Heading
#
HEADING_TMPL = """<div class='heading'>
<h1 style="font-family: Microsoft YaHei">%(title)s</h1>
%(parameters)s
<p class='description'>%(description)s</p>
</div>
""" # variables: (title, parameters, description)
HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s : </strong> %(value)s</p>
""" # variables: (name, value)
# ------------------------------------------------------------------------
# Report
#
# 汉化,加美化效果 --Yang Yao Jun
#
# 这里涉及到了 Bootstrap 前端技术,Bootstrap 按钮 资料介绍详见:http://www.runoob.com/bootstrap/bootstrap-buttons.html
#
REPORT_TMPL = """
<p id='show_detail_line'>
<a class="btn btn-primary" href='javascript:showCase(0)'>通过率 [%(passrate)s ]</a>
<a class="btn btn-success" href='javascript:showCase(2)'>通过[ %(Pass)s ]</a>
<a class="btn btn-warning" href='javascript:showCase(3)'>错误[ %(error)s ]</a>
<a class="btn btn-danger" href='javascript:showCase(1)'>失败[ %(fail)s ]</a>
<a class="btn btn-info" href='javascript:showCase(4)'>所有[ %(count)s ]</a>
</p>
<table id='result_table' class="table table-condensed table-bordered table-hover">
<colgroup>
<col align='left' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
</colgroup>
<tr id='header_row' class="text-center success" style="font-weight: bold;font-size: 14px;">
<td>用例集/测试用例</td>
<td>总计</td>
<td>通过</td>
<td>错误</td>
<td>失败</td>
<td>详细</td>
</tr>
%(test_list)s
<tr id='total_row' class="text-center active">
<td>总计</td>
<td>%(count)s</td>
<td>%(Pass)s</td>
<td>%(error)s</td>
<td>%(fail)s</td>
<td>通过率:%(passrate)s</td>
</tr>
</table>
""" # variables: (test_list, count, Pass, fail, error ,passrate)
REPORT_CLASS_TMPL = r"""
<tr class='%(style)s warning'>
<td>%(desc)s</td>
<td class="text-center">%(count)s</td>
<td class="text-center">%(Pass)s</td>
<td class="text-center">%(error)s</td>
<td class="text-center">%(fail)s</td>
<td class="text-center"><a href="javascript:showClassDetail('%(cid)s',%(count)s)" class="detail" id='%(cid)s'>详细</a></td>
</tr>
""" # variables: (style, desc, count, Pass, fail, error, cid)
# 失败 的样式,去掉原来JS效果,美化展示效果 -Findyou
REPORT_TEST_WITH_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'>
<td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
<td colspan='5' align='center'>
<!--默认收起错误信息 -Findyou
<button id='btn_%(tid)s' type="button" class="btn btn-danger btn-xs collapsed" data-toggle="collapse" data-target='#div_%(tid)s'>%(status)s</button>
<div id='div_%(tid)s' class="collapse"> -->
<!-- 默认展开错误信息 -Findyou -->
<button id='btn_%(tid)s' type="button" class="btn btn-danger btn-xs" data-toggle="collapse" data-target='#div_%(tid)s'>%(status)s</button>
<div id='div_%(tid)s' class="collapse in" style='text-align: left; color:red;cursor:pointer'>
<pre>
%(script)s
</pre>
</div>
</td>
</tr>
""" # variables: (tid, Class, style, desc, status)
# 通过 的样式,加标签效果 -Findyou
REPORT_TEST_NO_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'>
<td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
<td colspan='5' align='center'><span class="label label-success success">%(status)s</span></td>
</tr>
""" # variables: (tid, Class, style, desc, status)
REPORT_TEST_OUTPUT_TMPL = r"""
%(id)s: %(output)s
""" # variables: (id, output)
# ------------------------------------------------------------------------
# ENDING
#
# 增加返回顶部按钮 --Findyou
ENDING_TMPL = """<div id='ending'> </div>
<div style=" position:fixed;right:50px; bottom:30px; width:20px; height:20px;cursor:pointer">
<a href="#"><span class="glyphicon glyphicon-eject" style = "font-size:30px;" aria-hidden="true">
</span></a></div>
"""
# -------------------- The end of the Template class -------------------
TestResult = unittest.TestResult
class _TestResult(TestResult):
# note: _TestResult is a pure representation of results.
# It lacks the output and reporting ability compares to unittest._TextTestResult.
def __init__(self, verbosity=1):
TestResult.__init__(self)
self.stdout0 = None
self.stderr0 = None
self.success_count = 0
self.failure_count = 0
self.error_count = 0
self.verbosity = verbosity
# result is a list of result in 4 tuple
# (
# result code (0: success; 1: fail; 2: error),
# TestCase object,
# Test output (byte string),
# stack trace,
# )
self.result = []
# 增加一个测试通过率 --Findyou
self.passrate = float(0)
def startTest(self, test):
TestResult.startTest(self, test)
# just one buffer for both stdout and stderr
self.outputBuffer = io.StringIO()
stdout_redirector.fp = self.outputBuffer
stderr_redirector.fp = self.outputBuffer
self.stdout0 = sys.stdout
self.stderr0 = sys.stderr
sys.stdout = stdout_redirector
sys.stderr = stderr_redirector
def complete_output(self):
"""
Disconnect output redirection and return buffer.
Safe to call multiple times.
"""
if self.stdout0:
sys.stdout = self.stdout0
sys.stderr = self.stderr0
self.stdout0 = None
self.stderr0 = None
return self.outputBuffer.getvalue()
def stopTest(self, test):
# Usually one of addSuccess, addError or addFailure would have been called.
# But there are some path in unittest that would bypass this.
# We must disconnect stdout in stopTest(), which is guaranteed to be called.
self.complete_output()
def addSuccess(self, test):
self.success_count += 1
TestResult.addSuccess(self, test)
output = self.complete_output()
self.result.append((0, test, output, ''))
if self.verbosity > 1:
sys.stderr.write('ok ')
sys.stderr.write(str(test))
sys.stderr.write('\n')
else:
sys.stderr.write('.')
def addError(self, test, err):
self.error_count += 1
TestResult.addError(self, test, err)
_, _exc_str = self.errors[-1]
output = self.complete_output()
self.result.append((2, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write('E ')
sys.stderr.write(str(test))
sys.stderr.write('\n')
else:
sys.stderr.write('E')
def addFailure(self, test, err):
self.failure_count += 1
TestResult.addFailure(self, test, err)
_, _exc_str = self.failures[-1]
output = self.complete_output()
self.result.append((1, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write('F ')
sys.stderr.write(str(test))
sys.stderr.write('\n')
else:
sys.stderr.write('F')
class HTMLTestRunner(Template_mixin):
"""
"""
def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None, tester=None):
self.stream = stream
self.verbosity = verbosity
if title is None:
self.title = self.DEFAULT_TITLE
else:
self.title = title
if description is None:
self.description = self.DEFAULT_DESCRIPTION
else:
self.description = description
if tester is None:
self.tester = self.DEFAULT_TESTER
else:
self.tester = tester
self.startTime = datetime.datetime.now()
def run(self, test):
"Run the given test case or test suite."
result = _TestResult(self.verbosity)
test(result)
self.stopTime = datetime.datetime.now()
self.generateReport(test, result)
print('\nTime Elapsed: %s' % (self.stopTime - self.startTime), file=sys.stderr)
return result
def sortResult(self, result_list):
# unittest does not seems to run in any particular order.
# Here at least we want to group them together by class.
rmap = {}
classes = []
for n, t, o, e in result_list:
cls = t.__class__
if cls not in rmap:
rmap[cls] = []
classes.append(cls)
rmap[cls].append((n, t, o, e))
r = [(cls, rmap[cls]) for cls in classes]
return r
# 替换测试结果status为通过率 --Findyou
def getReportAttributes(self, result):
"""
Return report attributes as a list of (name, value).
Override this to add custom attributes.
"""
startTime = str(self.startTime)[:19]
duration = str(self.stopTime - self.startTime)
status = []
status.append('共 %s' % (result.success_count + result.failure_count + result.error_count))
if result.success_count:
status.append('通过 %s' % result.success_count)
if result.failure_count:
status.append('失败 %s' % result.failure_count)
if result.error_count:
status.append('错误 %s' % result.error_count)
if status:
status = ','.join(status)
self.passrate = str("%.2f%%" % (float(result.success_count) / float(
result.success_count + result.failure_count + result.error_count) * 100))
else:
status = 'none'
return [
('测试人员', self.tester),
('开始时间', startTime),
('合计耗时', duration),
('测试结果', status + ",通过率= " + self.passrate),
]
def generateReport(self, test, result):
report_attrs = self.getReportAttributes(result)
generator = 'HTMLTestRunner %s' % __version__
stylesheet = self._generate_stylesheet()
heading = self._generate_heading(report_attrs)
report = self._generate_report(result)
ending = self._generate_ending()
chart = self._generate_chart(result)
output = self.HTML_TMPL % dict(
title=saxutils.escape(self.title),
generator=generator,
stylesheet=stylesheet,
heading=heading,
report=report,
ending=ending,
chart_script=chart
)
self.stream.write(output.encode('utf8'))
def _generate_stylesheet(self):
return self.STYLESHEET_TMPL
# 增加Tester显示 -Findyou
def _generate_heading(self, report_attrs):
a_lines = []
for name, value in report_attrs:
line = self.HEADING_ATTRIBUTE_TMPL % dict(
name=saxutils.escape(name),
value=saxutils.escape(value),
)
a_lines.append(line)
heading = self.HEADING_TMPL % dict(
title=saxutils.escape(self.title),
parameters=''.join(a_lines),
description=saxutils.escape(self.description),
tester=saxutils.escape(self.tester),
)
return heading
# 生成报告 --Findyou添加注释
def _generate_report(self, result):
rows = []
sortedResult = self.sortResult(result.result)
for cid, (cls, cls_results) in enumerate(sortedResult):
# subtotal for a class
np = nf = ne = 0
for n, t, o, e in cls_results:
if n == 0:
np += 1
elif n == 1:
nf += 1
else:
ne += 1
# format class description
if cls.__module__ == "__main__":
name = cls.__name__
else:
name = "%s.%s" % (cls.__module__, cls.__name__)
doc = cls.__doc__ and cls.__doc__.split("\n")[0] or ""
desc = doc and '%s: %s' % (name, doc) or name
row = self.REPORT_CLASS_TMPL % dict(
style=ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
desc=desc,
count=np + nf + ne,
Pass=np,
fail=nf,
error=ne,
cid='c%s' % (cid + 1),
)
rows.append(row)
for tid, (n, t, o, e) in enumerate(cls_results):
self._generate_report_test(rows, cid, tid, n, t, o, e)
report = self.REPORT_TMPL % dict(
test_list=''.join(rows),
count=str(result.success_count + result.failure_count + result.error_count),
Pass=str(result.success_count),
fail=str(result.failure_count),
error=str(result.error_count),
passrate=self.passrate,
)
return report
def _generate_chart(self, result):
chart = self.ECHARTS_SCRIPT % dict(
Pass=str(result.success_count),
fail=str(result.failure_count),
error=str(result.error_count),
)
return chart
def _generate_report_test(self, rows, cid, tid, n, t, o, e):
# e.g. 'pt1.1', 'ft1.1', etc
has_output = bool(o or e)
# ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou
tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid + 1, tid + 1)
name = t.id().split('.')[-1]
doc = t.shortDescription() or ""
desc = doc and ('%s: %s' % (name, doc)) or name
tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL
# utf-8 支持中文 - Findyou
# o and e should be byte string because they are collected from stdout and stderr?
if isinstance(o, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# uo = unicode(o.encode('string_escape'))
# uo = o.decode('latin-1')
uo = o
else:
uo = o
if isinstance(e, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# ue = unicode(e.encode('string_escape'))
# ue = e.decode('latin-1')
ue = e
else:
ue = e
script = self.REPORT_TEST_OUTPUT_TMPL % dict(
id=tid,
output=saxutils.escape(uo + ue),
)
row = tmpl % dict(
tid=tid,
Class=(n == 0 and 'hiddenRow' or 'none'),
style=n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'),
desc=desc,
script=script,
status=self.STATUS[n],
)
rows.append(row)
if not has_output:
return
def _generate_ending(self):
return self.ENDING_TMPL
##############################################################################
# Facilities for running tests from the command line
##############################################################################
# Note: Reuse unittest.TestProgram to launch test. In the future we may
# build our own launcher to support more specific command line
# parameters like test title, CSS, etc.
class TestProgram(unittest.TestProgram):
"""
A variation of the unittest.TestProgram. Please refer to the base
class for command line parameters.
"""
def runTests(self):
# Pick HTMLTestRunner as the default test runner.
# base class's testRunner parameter is not useful because it means
# we have to instantiate HTMLTestRunner before we know self.verbosity.
if self.testRunner is None:
self.testRunner = HTMLTestRunner(verbosity=self.verbosity)
unittest.TestProgram.runTests(self)
main = TestProgram
##############################################################################
# Executing this module from the command line
##############################################################################
if __name__ == "__main__":
main(module=None)
# -*- coding: utf-8 -*-
# @Time : 2020/7/15 15:22
# @Author : wangyinghao
# @FileName: __init__.py.py
# @Software: PyCharm
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>API测试报告</title>
<meta name="generator" content="HTMLTestRunner 0.8.2.3"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcss.com/echarts/3.8.5/echarts.common.min.js"></script>
<!-- <script type="text/javascript" src="js/echarts.common.min.js"></script> -->
<style type="text/css" media="screen">
body { font-family: Microsoft YaHei,Tahoma,arial,helvetica,sans-serif; font-size: 80%; }
table { font-size: 100%; }
pre { white-space: pre-wrap;word-wrap: break-word; }
/* -- heading ---------------------------------------------------------------------- */
h1 {
font-size: 16pt;
color: gray;
}
.heading {
margin-top: 0ex;
margin-bottom: 1ex;
}
.heading .attribute {
margin-top: 1ex;
margin-bottom: 0;
}
.heading .description {
margin-top: 2ex;
margin-bottom: 3ex;
}
/* -- css div popup ------------------------------------------------------------------------ */
a.popup_link {
}
a.popup_link:hover {
color: red;
}
.popup_window {
display: none;
position: relative;
left: 0px;
top: 0px;
/*border: solid #627173 1px; */
padding: 10px;
/* */
font-family: "Lucida Console", "Courier New", Courier, monospace;
text-align: left;
font-size: 8pt;
/* width: 500px;*/
}
/* -- report ------------------------------------------------------------------------ */
#total_row { font-weight: bold; }
.passCase { color: #5cb85c; }
.failCase { color: #d9534f; font-weight: bold; }
.errorCase { color: #f0ad4e; font-weight: bold; }
.hiddenRow { display: none; }
.testcase { margin-left: 2em; }
</style>
</head>
<body >
<script language="javascript" type="text/javascript">
output_list = Array();
/*level 调整增加只显示通过用例的分类 --Adil
0:Summary //all hiddenRow
1:Failed //pt hiddenRow, ft none
2:Pass //pt none, ft hiddenRow
3:Error // pt hiddenRow, ft none
4:All //pt none, ft none
下面设置 按钮展开逻辑 --Yang Yao Jun
*/
function showCase(level) {
trs = document.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++) {
tr = trs[i];
id = tr.id;
if (id.substr(0,2) == 'ft') {
if (level == 2 || level == 0 ) {
tr.className = 'hiddenRow';
}
else {
tr.className = '';
}
}
if (id.substr(0,2) == 'pt') {
if (level < 2 || level ==3 ) {
tr.className = 'hiddenRow';
}
else {
tr.className = '';
}
}
}
//加入【详细】切换文字变化 --Findyou
detail_class=document.getElementsByClassName('detail');
//console.log(detail_class.length)
if (level == 3) {
for (var i = 0; i < detail_class.length; i++){
detail_class[i].innerHTML="收起"
}
}
else{
for (var i = 0; i < detail_class.length; i++){
detail_class[i].innerHTML="详细"
}
}
}
function showClassDetail(cid, count) {
var id_list = Array(count);
var toHide = 1;
for (var i = 0; i < count; i++) {
//ID修改 点 为 下划线 -Findyou
tid0 = 't' + cid.substr(1) + '_' + (i+1);
tid = 'f' + tid0;
tr = document.getElementById(tid);
if (!tr) {
tid = 'p' + tid0;
tr = document.getElementById(tid);
}
id_list[i] = tid;
if (tr.className) {
toHide = 0;
}
}
for (var i = 0; i < count; i++) {
tid = id_list[i];
//修改点击无法收起的BUG,加入【详细】切换文字变化 --Findyou
if (toHide) {
document.getElementById(tid).className = 'hiddenRow';
document.getElementById(cid).innerText = "详细"
}
else {
document.getElementById(tid).className = '';
document.getElementById(cid).innerText = "收起"
}
}
}
function html_escape(s) {
s = s.replace(/&/g,'&');
s = s.replace(/</g,'<');
s = s.replace(/>/g,'>');
return s;
}
</script>
<div id="div_base">
<div class='heading'>
<h1 style="font-family: Microsoft YaHei">API测试报告</h1>
<p class='attribute'><strong>测试人员 : </strong> QA</p>
<p class='attribute'><strong>开始时间 : </strong> 2021-04-26 15:24:03</p>
<p class='attribute'><strong>合计耗时 : </strong> 0:00:12.086054</p>
<p class='attribute'><strong>测试结果 : </strong> 共 1,通过 1,通过率= 100.00%</p>
<p class='description'>2021-04-26-15:24:03</p>
</div>
<p id='show_detail_line'>
<a class="btn btn-primary" href='javascript:showCase(0)'>通过率 [100.00% ]</a>
<a class="btn btn-success" href='javascript:showCase(2)'>通过[ 1 ]</a>
<a class="btn btn-warning" href='javascript:showCase(3)'>错误[ 0 ]</a>
<a class="btn btn-danger" href='javascript:showCase(1)'>失败[ 0 ]</a>
<a class="btn btn-info" href='javascript:showCase(4)'>所有[ 1 ]</a>
</p>
<table id='result_table' class="table table-condensed table-bordered table-hover">
<colgroup>
<col align='left' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
</colgroup>
<tr id='header_row' class="text-center success" style="font-weight: bold;font-size: 14px;">
<td>用例集/测试用例</td>
<td>总计</td>
<td>通过</td>
<td>错误</td>
<td>失败</td>
<td>详细</td>
</tr>
<tr class='passClass warning'>
<td>InterfaceTest</td>
<td class="text-center">1</td>
<td class="text-center">1</td>
<td class="text-center">0</td>
<td class="text-center">0</td>
<td class="text-center"><a href="javascript:showClassDetail('c1',1)" class="detail" id='c1'>详细</a></td>
</tr>
<tr id='pt1_1' class='hiddenRow'>
<td class='passCase'><div class='testcase'>test_run_cases_00001_内置商城: test_run_cases_00001_内置商城</div></td>
<td colspan='5' align='center'>
<!--默认收起错误信息 -Findyou
<button id='btn_pt1_1' type="button" class="btn btn-danger btn-xs collapsed" data-toggle="collapse" data-target='#div_pt1_1'>通过</button>
<div id='div_pt1_1' class="collapse"> -->
<!-- 默认展开错误信息 -Findyou -->
<button id='btn_pt1_1' type="button" class="btn btn-danger btn-xs" data-toggle="collapse" data-target='#div_pt1_1'>通过</button>
<div id='div_pt1_1' class="collapse in" style='text-align: left; color:red;cursor:pointer'>
<pre>
pt1_1: 测试用例ID: 16
测试用例名称: 获取资源
断言失败,用例名称是:获取资源
'"msg":"OK"' not found in '{\'code\': \'0\', \'msg\': \'OK\', \'data\': {\'totalResult\': 222, \'totalPage\': 12, \'sort\': 0, \'terminal\': "\'20002\'", \'rows\': 20, \'itemId\': \'\', \'itemName\': \'\', \'ifSale\': 10011, \'price\': \'\', \'currentResult\': [{\'sysId\': 190, \'itemId\': \'c9f9d26ed03b44e583ad40e24880cc12\', \'itemCode\': \'VT_200430007\', \'resourceId\': \'4b0511e501744e6e97b7a6db83042395\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 71323, \'itemName\': \'广西省全域旅游大数据\', \'itemVideo\': \'https://files.raykite.com/raydata/20200426/video/f6488884209d4fa494c09eefed5f4098.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200426/image/0472595307a54fdebcaaa5d1c3f029fe.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS84NWVjODViMjExYTQ0NjdjYTQ2YzM4MjM0N2M3Y2ZhNy5qcGciLz48L2Rpdj48cD48L3A+PHA+PC9wPjxwPjwvcD4=\', \'ifFree\': 10031, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588169623757, \'choiceness\': 0, \'saleNum\': 1430, \'browseNum\': 19315, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,文旅,全域旅游,广西省,地图,景点\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1587897677246, \'updateTime\': 1618294834505, \'itemResourcePrice\': {\'itemId\': \'c9f9d26ed03b44e583ad40e24880cc12\', \'originalPrice\': 100.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'4b0511e501744e6e97b7a6db83042395\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200707/files/RayData_%E5%B9%BF%E8%A5%BF%E7%9C%81%E5%85%A8%E5%9F%9F%E6%97%85%E6%B8%B8%E5%A4%A7%E6%95%B0%E6%8D%AE_1920X1080_VT_200430007.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 11, \'uploadTime\': 1616494240000}, \'user\': None, \'hits\': 2096, \'collection\': 10, \'resourceDownloads\': 237, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 206, \'itemId\': \'fc6d950c45d442bda749d07fd0e89e25\', \'itemCode\': \'VT_200430002\', \'resourceId\': \'82c93c177c9e4cd5858fa6c3209687c3\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 284786, \'itemName\': \'社区人口管理\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/b0a82770cd02438db150d9e93147e49a.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/0c7f97068e484382bac16cb4184eace9.png\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS8zYTg4Y2NmYzQ3YmM0Yzk5ODE5YTIyNmM3ODViYTM4Ni5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1618296505896, \'choiceness\': 0, \'saleNum\': 1006, \'browseNum\': 11880, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,社区,人口,楼层,管理\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588054051255, \'updateTime\': 1618296505896, \'itemResourcePrice\': {\'itemId\': \'fc6d950c45d442bda749d07fd0e89e25\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'82c93c177c9e4cd5858fa6c3209687c3\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200707/files/RayData_%E7%A4%BE%E5%8C%BA%E4%BA%BA%E5%8F%A3%E7%AE%A1%E7%90%86_1920X1080_VT_200430002.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 5, \'uploadTime\': 1594096079000}, \'user\': None, \'hits\': 1435, \'collection\': 10, \'resourceDownloads\': 168, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 47, \'itemId\': \'700df2454c1e4f97b0ff8a269925ea5c\', \'itemCode\': \'TM_ETH_191015001\', \'resourceId\': \'b9d1ff5bc3cf4bf6802d6c7ff9f62fa1\', \'terminal\': 20002, \'resourcePromulgator\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'resourceSize\': 42548, \'itemName\': \'地球板块A\', \'itemVideo\': \'https://files.raykite.com/raydata/20200429/video/827f643ca3b1413fad0ab688fdaf8098.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/77b467c57f0b435e8444f3aec113e371.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDI2L2ltYWdlLzk5NzMxOTU2Mjc4MjQ3YjBiMDM4NjNiMGMxNzZiNzAzLmpwZyIvPjwvZGl2PjxwPjwvcD4=\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1618296512348, \'choiceness\': 0, \'saleNum\': 733, \'browseNum\': 8456, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地球,板块,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'createTime\': 1566407270119, \'updateTime\': 1618296512348, \'itemResourcePrice\': {\'itemId\': \'700df2454c1e4f97b0ff8a269925ea5c\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,卫星版图\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'b9d1ff5bc3cf4bf6802d6c7ff9f62fa1\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E5%9C%B0%E7%90%83%E6%9D%BF%E5%9D%97A_1920_1080_TM_ETH_191015001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 8, \'uploadTime\': 1609152690000}, \'user\': None, \'hits\': 941, \'collection\': 9, \'resourceDownloads\': 122, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 189, \'itemId\': \'671c714350454b6bb4f31f5ff5791b3c\', \'itemCode\': \'VT_200430001\', \'resourceId\': \'a39a259771874ce0b789cc807d63bc6b\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 197877, \'itemName\': \'战斗机信息可视化\', \'itemVideo\': \'https://files.raykite.com/raydata/20200426/video/7367cd79c7d441469c6dcb21afff239b.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200426/image/53020ad88db54d6a92e7243deaa267b3.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS9hZmNkNWZhMWY3MTQ0M2VmOTgzN2QzNzQ5NTgzYWU3OC5qcGciLz48L2Rpdj48cD48L3A+PHA+PC9wPjxwPjwvcD4=\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588169617149, \'choiceness\': 0, \'saleNum\': 602, \'browseNum\': 7912, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,战斗机,飞机,可视化\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1587897554883, \'updateTime\': 1608876832490, \'itemResourcePrice\': {\'itemId\': \'671c714350454b6bb4f31f5ff5791b3c\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'a39a259771874ce0b789cc807d63bc6b\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200707/files/RayData_%E6%88%98%E6%96%97%E6%9C%BA%E4%BF%A1%E6%81%AF%E5%8F%AF%E8%A7%86%E5%8C%96_1920X1080_VT_200430001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 6, \'uploadTime\': 1594093902000}, \'user\': None, \'hits\': 827, \'collection\': 3, \'resourceDownloads\': 76, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 205, \'itemId\': \'02a1d8d7589b41e1a43034d3f3ac4c20\', \'itemCode\': \'VT_200430006\', \'resourceId\': \'034cf5fc290c45a8be0c612313ab9930\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 39368, \'itemName\': \'机架数据可视化\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/5a0f2ab735ca4b6db1e552a0726cd99e.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/afca34c32e7a409d9225ec2c6e677577.png\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS9kZWI4MDgxYzZiNDQ0NmU4ODljYjUzNDFjYTU2YzI1Ni5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10031, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588249160321, \'choiceness\': 0, \'saleNum\': 569, \'browseNum\': 7359, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,机架,互联网,机房,状态监控\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588053548404, \'updateTime\': 1618218908749, \'itemResourcePrice\': {\'itemId\': \'02a1d8d7589b41e1a43034d3f3ac4c20\', \'originalPrice\': 1.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'034cf5fc290c45a8be0c612313ab9930\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200707/files/RayData_%E6%9C%BA%E6%9E%B6%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%A7%86%E5%8C%96_1920X1080_VT_200430006.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 7, \'uploadTime\': 1616556844000}, \'user\': None, \'hits\': 848, \'collection\': 4, \'resourceDownloads\': 103, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 204, \'itemId\': \'bebfb2084441445a828d838e339ce0d6\', \'itemCode\': \'VT_200430004\', \'resourceId\': \'db210d12de4741ccb1d09a6d55eb874c\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 167021, \'itemName\': \'网上政务大数据\', \'itemVideo\': \'https://files.raykite.com/raydata/20200605/video/e830787dc86a41a38c6510540485f509.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200605/image/07ae1221c30943a8827283017fa06c4b.png\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDYwNS9pbWFnZS9hNjgyMGFhYzQzMjQ0MjNiOWY1ZDEzZjc0ZWUxMzhjOC5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPjxwPjwvcD48cD48L3A+\', \'ifFree\': 10031, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1615541818245, \'choiceness\': 0, \'saleNum\': 485, \'browseNum\': 6646, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,大数据,广东省,政务,可视化,线上办理\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588053299903, \'updateTime\': 1618386253121, \'itemResourcePrice\': {\'itemId\': \'bebfb2084441445a828d838e339ce0d6\', \'originalPrice\': 1.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'db210d12de4741ccb1d09a6d55eb874c\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200722/files/Raydata_%E7%BD%91%E4%B8%8A%E6%94%BF%E5%8A%A1%E5%A4%A7%E6%95%B0%E6%8D%AE_1920_1080_VT_200430004.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 9, \'uploadTime\': 1616563679000}, \'user\': None, \'hits\': 891, \'collection\': 6, \'resourceDownloads\': 61, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 208, \'itemId\': \'709e25c70e774985839960b4da883885\', \'itemCode\': \'BM_200430003\', \'resourceId\': \'ef8679ac709e4c078af45eac824fb53b\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 122269, \'itemName\': \'成都天府商圈\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/f95698773cf64811a21c551ad257fc16.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/cbbb00aa9f4445ff8a142e85a8ccd1ad.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS82ZmZhODQ2OTg3ZjA0MTNjOGQ1MTVkM2U2NDFmNWMxOC5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10031, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588246743631, \'choiceness\': 0, \'saleNum\': 449, \'browseNum\': 5701, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地标,四川,城市,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588054674715, \'updateTime\': 1618370397168, \'itemResourcePrice\': {\'itemId\': \'709e25c70e774985839960b4da883885\', \'originalPrice\': 1.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,城市建筑\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'ef8679ac709e4c078af45eac824fb53b\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E6%88%90%E9%83%BD%E5%A4%A9%E5%BA%9C%E5%95%86%E5%9C%88_1920_1080_BM_200430003.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 5, \'uploadTime\': 1616563896000}, \'user\': None, \'hits\': 733, \'collection\': 7, \'resourceDownloads\': 71, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 203, \'itemId\': \'7d772d408d664eae9731f530c52f31e6\', \'itemCode\': \'UI_CHART_200430003\', \'resourceId\': \'e369e04061684fa4a27807ae3bcb7c53\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 5999, \'itemName\': \'政务基础库\', \'itemVideo\': \'https://files.raykite.com/raydata/20200708/video/5e6b5dcdd70e44359f771adc978a412c.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200708/image/165e19f275194cf280f3b07601b1982f.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDcwOC9pbWFnZS82ZjRjMWY0MDQ3ZTg0NzE1YjA4ZTNmM2ZhZjQ0NDE1Ni5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': 1587830400000, \'endTime\': 1593187199000, \'ifSale\': 10011, \'saleTime\': 1618296750666, \'choiceness\': 0, \'saleNum\': 423, \'browseNum\': 5005, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'组合,图表,政务,政府\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1587910058622, \'updateTime\': 1618296750666, \'itemResourcePrice\': {\'itemId\': \'7d772d408d664eae9731f530c52f31e6\', \'originalPrice\': 50.0, \'discountsPrice\': 24.9}, \'labels\': None, \'category\': [\'信息图表\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'e369e04061684fa4a27807ae3bcb7c53\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201021/files/Raydata_%E6%94%BF%E5%8A%A1%E5%9F%BA%E7%A1%80%E5%BA%93_1920x1080_UI_CHART_200430003.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 13, \'uploadTime\': 1609137075000}, \'user\': None, \'hits\': 418, \'collection\': 3, \'resourceDownloads\': 58, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 300, \'itemId\': \'747ffbd5915340489ed746cff46b7fd6\', \'itemCode\': \'VT_200514002\', \'resourceId\': \'bd6fbab73b8949a4b35f79bb16b33a1b\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 294025, \'itemName\': \'智慧建筑可视化\', \'itemVideo\': \'https://files.raykite.com/raydata/20200605/video/28c2c8c992c14c6e8d20f50f3ed421ec.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200529/image/dbb8e27e51814887b361e9103c2bf458.png\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDUyOS9pbWFnZS81ZDI5NDk4M2NjZTc0ZDg2YTFmZGZhMDNlZGJjY2JkNi5wbmciLz48L2Rpdj48cD48L3A+\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1591355169547, \'choiceness\': 0, \'saleNum\': 455, \'browseNum\': 4797, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,保利,建筑,安防,电梯,资源\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1590741167529, \'updateTime\': 1608884096346, \'itemResourcePrice\': {\'itemId\': \'747ffbd5915340489ed746cff46b7fd6\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'bd6fbab73b8949a4b35f79bb16b33a1b\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200605/files/RayData_%E6%99%BA%E6%85%A7%E5%BB%BA%E7%AD%91%E5%8F%AF%E8%A7%86%E5%8C%96_1920_1080_VT_200514002.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 5, \'uploadTime\': 1591355167000}, \'user\': None, \'hits\': 716, \'collection\': 7, \'resourceDownloads\': 91, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 44, \'itemId\': \'e8fddd4cf9324ed18251fa7a204a89ae\', \'itemCode\': \'UI_CHART_190821001\', \'resourceId\': \'184af558c4644812b6494d4576f19ff7\', \'terminal\': 20002, \'resourcePromulgator\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'resourceSize\': 5785, \'itemName\': \'梦幻奥兰多\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/image/e5033575bf294986880106157bbc3974.jpg\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/e5033575bf294986880106157bbc3974.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iMCIgX3Jvb3Q9InVuZGVmaW5lZCIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNjA4L2ltYWdlL2IwOTg1NTVhZjFkMTQzNGQ4YmYyZDdmY2RiMjdiOWFmLnBuZyIvPjwvZGl2PjxwPjwvcD48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': 1587830400000, \'endTime\': 1593187199000, \'ifSale\': 10011, \'saleTime\': 1588167918217, \'choiceness\': 0, \'saleNum\': 262, \'browseNum\': 3871, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'组合,图表,梦幻紫,薰衣草风格\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'createTime\': 1566405299394, \'updateTime\': 1609136892877, \'itemResourcePrice\': {\'itemId\': \'e8fddd4cf9324ed18251fa7a204a89ae\', \'originalPrice\': 50.0, \'discountsPrice\': 24.9}, \'labels\': None, \'category\': [\'信息图表\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'184af558c4644812b6494d4576f19ff7\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201021/files/Raydata_%E6%A2%A6%E5%B9%BB%E5%A5%A5%E5%85%B0%E5%A4%9A_1920x1080_UI_CHART_190821001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 13, \'uploadTime\': 1609136893000}, \'user\': None, \'hits\': 298, \'collection\': 3, \'resourceDownloads\': 37, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 88, \'itemId\': \'5944501832ff4844922aee3e6b962141\', \'itemCode\': \'BM_191015004\', \'resourceId\': \'e9e341c06589469b989bbd1a780ad37c\', \'terminal\': 20002, \'resourcePromulgator\': \'efc5427dbb68452f9cf676ad702653e4\', \'resourceSize\': 296343, \'itemName\': \'天河城商圈\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/d1f6fc4daabf4ba9a676f41b864460fd.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/0a451838c9e94b5ab9620a0edbf013db.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDMwL2ltYWdlLzQxYzhiY2ZkY2Y1NDRmNjZhMTQyMGNlMWU0YjBiYmRjLnBuZyIvPjwvZGl2PjxwPjwvcD4=\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588246687955, \'choiceness\': 0, \'saleNum\': 335, \'browseNum\': 3734, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地标,广州,天河,城市,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'efc5427dbb68452f9cf676ad702653e4\', \'createTime\': 1571389166648, \'updateTime\': 1609140699788, \'itemResourcePrice\': {\'itemId\': \'5944501832ff4844922aee3e6b962141\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,城市建筑\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'e9e341c06589469b989bbd1a780ad37c\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E5%A4%A9%E6%B2%B3%E5%9F%8E%E5%95%86%E5%9C%88_1920_1080_BM_191015004.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 6, \'uploadTime\': 1609140700000}, \'user\': None, \'hits\': 0, \'collection\': 1, \'resourceDownloads\': 32, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 209, \'itemId\': \'b776e23e50904beb94c07c7e8376df6c\', \'itemCode\': \'UI_CHART_200430004\', \'resourceId\': \'d68b624b52794ca0852973235527ede6\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 19444, \'itemName\': \'景区管理\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/cf4a785dfae0443784d915529f7e8dde.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/a03b078bac7e481a8c6085a2ea071761.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDQzMC9pbWFnZS8xNTkwZmNlOWQzZGM0ZjNiOWFiZWM4OWZiZmE0OTRhYi5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': 1587830400000, \'endTime\': 1593187199000, \'ifSale\': 10011, \'saleTime\': 1590070333575, \'choiceness\': 0, \'saleNum\': 303, \'browseNum\': 3374, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'组合,图表,文旅,旅游,全域旅游\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588056599229, \'updateTime\': 1609137130339, \'itemResourcePrice\': {\'itemId\': \'b776e23e50904beb94c07c7e8376df6c\', \'originalPrice\': 50.0, \'discountsPrice\': 24.9}, \'labels\': None, \'category\': [\'信息图表\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'d68b624b52794ca0852973235527ede6\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201021/files/Raydata_%E6%99%AF%E5%8C%BA%E7%AE%A1%E7%90%86_1920x1080_UI_CHART_200430004.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 11, \'uploadTime\': 1609137130000}, \'user\': None, \'hits\': 395, \'collection\': 3, \'resourceDownloads\': 50, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 50, \'itemId\': \'eaa07d7ccf904bf1b4b816e1284065ba\', \'itemCode\': \'BM_191015003\', \'resourceId\': \'98a54ee2bacc49f194b17693acee3b56\', \'terminal\': 20002, \'resourcePromulgator\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'resourceSize\': 490160, \'itemName\': \'上海外滩区域\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/c26c70e8fd96445eae6616a5ca92b752.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/ea2dec6d61b14270b46d955abf4394f0.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDMwL2ltYWdlL2Q4MWQ1ZjcwYjg3MjRmMWFhZmE5MjYyYTI4NmUzYjY1LnBuZyIvPjwvZGl2PjxwPjwvcD4=\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588246714461, \'choiceness\': 0, \'saleNum\': 221, \'browseNum\': 2816, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地标,上海,城市,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'createTime\': 1566436910211, \'updateTime\': 1609141146814, \'itemResourcePrice\': {\'itemId\': \'eaa07d7ccf904bf1b4b816e1284065ba\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,城市建筑\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'98a54ee2bacc49f194b17693acee3b56\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E4%B8%8A%E6%B5%B7%E5%A4%96%E6%BB%A9%E5%95%86%E5%9C%88_1920_1080_BM_191015003.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 4, \'uploadTime\': 1609141147000}, \'user\': None, \'hits\': 238, \'collection\': 1, \'resourceDownloads\': 16, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 53, \'itemId\': \'998dee06cd2648e193c0e8b607d81e4b\', \'itemCode\': \'TM_CN_191015001\', \'resourceId\': \'b05129b2bb2645b1bbdd0b7f7dca17ac\', \'terminal\': 20002, \'resourcePromulgator\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'resourceSize\': 41367, \'itemName\': \'中国板块\', \'itemVideo\': \'https://files.raykite.com/raydata/20200429/image/c3b048596bb04495a94db107a96b955b.jpg\', \'itemThumb\': \'https://files.raykite.com/raydata/20201019/image/c4004a9249e842a0990c709003852935.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDI2L2ltYWdlLzljYmYyMmQwY2UzYTQ5YWFhNmFmZjVlZWRhMWNjZDI3LmpwZyIvPjwvZGl2PjxwPjwvcD48cD48L3A+\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588165829097, \'choiceness\': 0, \'saleNum\': 223, \'browseNum\': 2453, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'中国,板块,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'cdadd2c6b6274ec8a1633c7e55b1895b\', \'createTime\': 1566437948292, \'updateTime\': 1609152637880, \'itemResourcePrice\': {\'itemId\': \'998dee06cd2648e193c0e8b607d81e4b\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,卫星版图\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'b05129b2bb2645b1bbdd0b7f7dca17ac\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201019/files/Raydata_%E4%B8%AD%E5%9B%BD%E7%89%88%E5%9D%97_1920_1080_TM_CN_191015001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 8, \'uploadTime\': 1609152638000}, \'user\': None, \'hits\': 225, \'collection\': 2, \'resourceDownloads\': 38, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 86, \'itemId\': \'e4fef2eac0104eff8456ddf5e9d7b147\', \'itemCode\': \'BM_191015002\', \'resourceId\': \'9f6d11d19f794879aa69544e1c7ccda2\', \'terminal\': 20002, \'resourcePromulgator\': \'efc5427dbb68452f9cf676ad702653e4\', \'resourceSize\': 220571, \'itemName\': \'国贸商圈\', \'itemVideo\': \'https://files.raykite.com/raydata/20200506/video/cf2889c95e3c43bfb31b86bacdbe2f6a.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/035ce8711a604ba4945aa4b5af223a16.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDMwL2ltYWdlLzhiMzVkYzZkOGI2MjQzMGZhMTMxYTNiMzJiNTU2MWU5LnBuZyIvPjwvZGl2PjxwPjwvcD48cD48L3A+\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588246653804, \'choiceness\': 0, \'saleNum\': 219, \'browseNum\': 2340, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地标,北京,朝阳,商业区,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'efc5427dbb68452f9cf676ad702653e4\', \'createTime\': 1571388934900, \'updateTime\': 1609140510010, \'itemResourcePrice\': {\'itemId\': \'e4fef2eac0104eff8456ddf5e9d7b147\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,城市建筑\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'9f6d11d19f794879aa69544e1c7ccda2\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E5%9B%BD%E8%B4%B8%E5%95%86%E5%9C%88_1920_1080_BM_191015002.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 10, \'uploadTime\': 1609140510000}, \'user\': None, \'hits\': 0, \'collection\': 2, \'resourceDownloads\': 29, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 202, \'itemId\': \'a1eb7b8190d04faa83933b0e485cbcf8\', \'itemCode\': \'UI_CHART_200430002\', \'resourceId\': \'716afbcffba746d2a4bcf29c52ebd7c7\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 6769, \'itemName\': \'园区物联\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/72bdaffd9a8f4d72b3bbb40532b436f5.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200426/image/32597d8332904c12aa69df17537d6377.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDYwOC9pbWFnZS8yZTZjYWI1OTYxNTk0ZjI0YTgxN2VkMjI5NzQ4ZjA4MS5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPjxwPjwvcD4=\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': 1587830400000, \'endTime\': 1593187199000, \'ifSale\': 10011, \'saleTime\': 1591604219347, \'choiceness\': 0, \'saleNum\': 0, \'browseNum\': 2261, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'组合,图表,园区,通用\', \'evaluate\': 0.0, \'ifShow\': 16000, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1587909894444, \'updateTime\': 1609137023785, \'itemResourcePrice\': {\'itemId\': \'a1eb7b8190d04faa83933b0e485cbcf8\', \'originalPrice\': 50.0, \'discountsPrice\': 24.9}, \'labels\': None, \'category\': [\'信息图表\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16010, \'itemOpenFiles\': {\'resourceId\': \'716afbcffba746d2a4bcf29c52ebd7c7\', \'resourceUrl\': \'\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 7, \'uploadTime\': 1588248290000}, \'user\': None, \'hits\': 419, \'collection\': 0, \'resourceDownloads\': 0, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 87, \'itemId\': \'71e6604dc57c41c8829fd5bae1041b2f\', \'itemCode\': \'BM_191015001\', \'resourceId\': \'3c99339c3da24eb8bea440b9245c5be2\', \'terminal\': 20002, \'resourcePromulgator\': \'efc5427dbb68452f9cf676ad702653e4\', \'resourceSize\': 135570, \'itemName\': \'望京商圈\', \'itemVideo\': \'https://files.raykite.com/raydata/20200430/video/420f3c0ec03e4265a7c0b1ecc19026dd.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200430/image/4c4fb5361d6b45a29acc5265d3cea617.jpg\', \'itemDetails\': \'PHAgc2l6ZT0iNSIgX3Jvb3Q9IltvYmplY3QgT2JqZWN0XSIgX19vd25lcmlkPSJ1bmRlZmluZWQiIF9faGFzaD0idW5kZWZpbmVkIiBfX2FsdGVyZWQ9ImZhbHNlIj48L3A+PGRpdiBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIj48aW1nIGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiIHNyYz0iaHR0cHM6Ly9maWxlcy5yYXlraXRlLmNvbS9yYXlkYXRhLzIwMjAwNDMwL2ltYWdlLzFiNzMyYWEwN2I2ZDQ2M2Q5YTM1NWUzM2I4N2FmYmIzLnBuZyIvPjwvZGl2PjxwPjwvcD48cD48L3A+\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1588246628693, \'choiceness\': 0, \'saleNum\': 145, \'browseNum\': 2066, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'地标,北京,互联网,模型,朝阳\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'efc5427dbb68452f9cf676ad702653e4\', \'createTime\': 1571388996990, \'updateTime\': 1609140533327, \'itemResourcePrice\': {\'itemId\': \'71e6604dc57c41c8829fd5bae1041b2f\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,城市建筑\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'3c99339c3da24eb8bea440b9245c5be2\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200515/files/Raydata_%E6%9C%9B%E4%BA%AC%E5%95%86%E5%9C%88_1920_1080_BM_191015001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 6, \'uploadTime\': 1609140533000}, \'user\': None, \'hits\': 0, \'collection\': 2, \'resourceDownloads\': 30, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 211, \'itemId\': \'962b29de115f4de59f8e779beb9bd7ab\', \'itemCode\': \'UI_CHART_200430006\', \'resourceId\': \'b330013b96994c87b67acbfd2f5c4ab6\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 6177, \'itemName\': \'机场管理\', \'itemVideo\': \'https://files.raykite.com/raydata/20200827/video/b92cc7000cd9403d9d50fd17b70bd7a6.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200605/image/9a25286ccbde42ddbb28c4320a0e1735.jpg\', \'itemDetails\': \'PHA+PC9wPjxwPjwvcD48ZGl2IGNsYXNzPSJtZWRpYS13cmFwIGltYWdlLXdyYXAiPjxpbWcgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCIgc3JjPSJodHRwczovL2ZpbGVzLnJheWtpdGUuY29tL3JheWRhdGEvMjAyMDA3MjgvaW1hZ2UvZDA0M2E1NDMxYTE5NDk5NGJmMzc5ZjQxMGNmODlmNjMucG5nIi8+PC9kaXY+PHA+PC9wPjxwPjwvcD48cD48L3A+\', \'ifFree\': 10035, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1591354198905, \'choiceness\': 0, \'saleNum\': 63, \'browseNum\': 2018, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'组合,图表,机场,行业,通用\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1588057117065, \'updateTime\': 1609137236453, \'itemResourcePrice\': {\'itemId\': \'962b29de115f4de59f8e779beb9bd7ab\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'信息图表\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'b330013b96994c87b67acbfd2f5c4ab6\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201021/files/Raydata_%E6%9C%BA%E5%9C%BA%E7%AE%A1%E7%90%86_1920x1080_UI_CHART_200430006.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 8, \'uploadTime\': 1609137236000}, \'user\': None, \'hits\': 340, \'collection\': 1, \'resourceDownloads\': 2, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 568, \'itemId\': \'b6585a729e714cc08694201590c7767c\', \'itemCode\': \'VT_200701001\', \'resourceId\': \'095aad6d64024297ac5e81711d4ae19d\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 290535, \'itemName\': \'机场管理可视化\', \'itemVideo\': \'https://files.raykite.com/raydata/20200729/video/acb245b5bbde468d92904851e1b62892.mp4\', \'itemThumb\': \'https://files.raykite.com/raydata/20200729/image/84efd89f4f754cb4986ef8d30728cb27.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDcyOS9pbWFnZS9iMzRjNWNlZDk0MWY0ZDkzOWU5ZDI0Mjc1MDRlZTdkNS5wbmciLz48L2Rpdj48cD48L3A+\', \'ifFree\': 10031, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1596018770858, \'choiceness\': 0, \'saleNum\': 154, \'browseNum\': 1913, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'模板,大兴机场,航班,机场\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1596017871363, \'updateTime\': 1618386400221, \'itemResourcePrice\': {\'itemId\': \'b6585a729e714cc08694201590c7767c\', \'originalPrice\': 1.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'系统模板\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'095aad6d64024297ac5e81711d4ae19d\', \'resourceUrl\': \'https://files.raykite.com/raydata/20200729/files/Raydata_%E6%9C%BA%E5%9C%BA%E7%AE%A1%E7%90%86%E5%8F%AF%E8%A7%86%E5%8C%96_1920_1080_VT_200701001.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 5, \'uploadTime\': 1617951413000}, \'user\': None, \'hits\': 554, \'collection\': 3, \'resourceDownloads\': 34, \'demoDownLoads\': 0, \'usageAmount\': 0}, {\'sysId\': 258, \'itemId\': \'7d1d6ae882354c668a15abcc397c93d9\', \'itemCode\': \'TM_CN_200514002\', \'resourceId\': \'eb1fde5d6a7c431e8fbd85e53138d79c\', \'terminal\': 20002, \'resourcePromulgator\': \'e48d9667a545442a9b8e7f43c7abc765\', \'resourceSize\': 80081, \'itemName\': \'中国板块C\', \'itemVideo\': \'https://files.raykite.com/raydata/20200527/image/eda96ff33a9748ef96eca43a7bcee491.jpg\', \'itemThumb\': \'https://files.raykite.com/raydata/20201019/image/6a200aa74d23409b8456e927aa60ed99.jpg\', \'itemDetails\': \'PHA+PC9wPjxkaXYgY2xhc3M9Im1lZGlhLXdyYXAgaW1hZ2Utd3JhcCI+PGltZyBjbGFzcz0ibWVkaWEtd3JhcCBpbWFnZS13cmFwIiBzcmM9Imh0dHBzOi8vZmlsZXMucmF5a2l0ZS5jb20vcmF5ZGF0YS8yMDIwMDUyOC9pbWFnZS83NzY4ZGVkZmQwN2M0NzdiYjZlMjM5MWNmODM5ZDBiZi5wbmciLz48L2Rpdj48cD48L3A+PHA+PC9wPg==\', \'ifFree\': 10030, \'ifDiscounts\': 10020, \'startTime\': None, \'endTime\': None, \'ifSale\': 10011, \'saleTime\': 1591351937515, \'choiceness\': 0, \'saleNum\': 202, \'browseNum\': 1889, \'initialSales\': 0, \'initialBrowse\': 0, \'tag\': \'中国,板块,模型\', \'evaluate\': 0.0, \'ifShow\': 16001, \'createBy\': \'e48d9667a545442a9b8e7f43c7abc765\', \'createTime\': 1590565831638, \'updateTime\': 1609149997389, \'itemResourcePrice\': {\'itemId\': \'7d1d6ae882354c668a15abcc397c93d9\', \'originalPrice\': 0.0, \'discountsPrice\': 0.0}, \'labels\': None, \'category\': [\'场景,卫星版图\'], \'imageUrl\': None, \'isKeep\': 0, \'isPay\': 0, \'isShopping\': 0, \'isSendLibrary\': None, \'isUpdate\': None, \'isOwn\': 0, \'ifDownload\': 16011, \'itemOpenFiles\': {\'resourceId\': \'eb1fde5d6a7c431e8fbd85e53138d79c\', \'resourceUrl\': \'https://files.raykite.com/raydata/20201019/files/Raydata_%E4%B8%AD%E5%9B%BD%E7%89%88%E5%9D%97C_1920_1080_TM_CN_200514002.rda\', \'resourceFormat\': \'RDA\', \'ppt\': \'\', \'uploadVersion\': 4, \'uploadTime\': 1609149997000}, \'user\': None, \'hits\': 373, \'collection\': 7, \'resourceDownloads\': 60, \'demoDownLoads\': 0, \'usageAmount\': 0}], \'page\': 1, \'statusData\': 10001, \'ifDownload\': \'\'}}'
测试用例ID: 17
测试用例名称: 获取解决方案
测试用例ID: 18
测试用例名称: 以标签分类查询全部资源推荐-cms
断言失败,用例名称是:以标签分类查询全部资源推荐-cms
"'msg': 'OK'" not found in '{"code":"0","msg":"OK","data":{"系统模板":[{"id":34,"itemId":"c9f9d26ed03b44e583ad40e24880cc12","itemType":1,"itemOrder":34,"operator":null,"itemName":"广西省全域旅游大数据","itemCode":"VT_200430007","ifSale":10011},{"id":37,"itemId":"671c714350454b6bb4f31f5ff5791b3c","itemType":1,"itemOrder":37,"operator":null,"itemName":"战斗机信息可视化","itemCode":"VT_200430001","ifSale":10011},{"id":38,"itemId":"fc6d950c45d442bda749d07fd0e89e25","itemType":1,"itemOrder":38,"operator":null,"itemName":"社区人口管理","itemCode":"VT_200430002","ifSale":10011}],"场景":[{"id":4,"itemId":"700df2454c1e4f97b0ff8a269925ea5c","itemType":1,"itemOrder":4,"operator":null,"itemName":"地球板块A","itemCode":"TM_ETH_191015001","ifSale":10011},{"id":13,"itemId":"7379c136f8934bc19f496c16f395016c","itemType":1,"itemOrder":13,"operator":null,"itemName":"徐汇区(仅支持v6.8版本)","itemCode":"CM_SH_XH_200514001","ifSale":10011},{"id":17,"itemId":"e4fef2eac0104eff8456ddf5e9d7b147","itemType":1,"itemOrder":17,"operator":null,"itemName":"国贸商圈","itemCode":"BM_191015002","ifSale":10011}]}}'
测试用例ID: 19
测试用例名称: 查询全部解决方案推荐
断言失败,用例名称是:查询全部解决方案推荐
"'msg': 'OK'" not found in '&lt;!DOCTYPE html&gt;\r\n&lt;html lang="en"&gt;\r\n\r\n&lt;head&gt;\r\n &lt;meta charset="utf-8" /&gt;\r\n &lt;meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /&gt;\r\n &lt;meta name="renderer" content="webkit" /&gt;\r\n &lt;meta name="viewport"\r\n content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, minimum-scale=1, user-scalable=no" /&gt;\r\n &lt;meta name="apple-mobile-web-app-capable" content="yes" /&gt;\r\n &lt;meta name="format-detection" content="telephone=no" /&gt;\r\n &lt;meta name="keywords" content="3D模å\x9e\x8bï¼\x8c3Då\x8f¯è§\x86å\x8c\x96ï¼\x8c3Dèµ\x84æº\x90å\x95\x86å\x9f\x8eï¼\x8cå\x9f\x8eå¸\x82建ç\xad\x91模å\x9e\x8bï¼\x8cå\x9b¾è¡¨ï¼\x8cå®\x9eæ\x97¶æ\x95°æ\x8d®ï¼\x8c3D设计å¸\x88ï¼\x8c3Dä½\x9cå\x93\x81å±\x95示ï¼\x8cè¡\x8cä¸\x9aè§£å\x86³æ\x96¹æ¡\x88ï¼\x8cå\x95\x86ä¸\x9aæ\x99ºè\x83½ï¼\x8cRayData Asset," /&gt;\r\n &lt;meta name="description"\r\n content="RayData Assetèµ\x84æº\x90å¹³å\x8f°æ\xad£å\x9c¨é\x80\x9aè¿\x873Då\x8f¯è§\x86å\x8c\x96ä½\x93éª\x8cæ\x94¹å\x8f\x98ä¸\x96ç\x95\x8cã\x80\x82å¹³å\x8f°æ\x8f\x90ä¾\x9bä¸\x93ä¸\x9a深度ç\x9a\x84è¡\x8cä¸\x9aè§£å\x86³æ\x96¹æ¡\x88ã\x80\x81ç²¾ç¾\x8eç\x82«é\x85·ç\x9a\x843D模å\x9e\x8bèµ\x84æº\x90ã\x80\x81æ\x96°é¢\x96å®\x9eç\x94¨ç\x9a\x84å\x9b¾è¡¨æ\xa0·å¼\x8f以å\x8f\x8aå¤\x9aæ\xa0·å\x8c\x96ç\x9a\x84ç´\xa0æ\x9d\x90帮å\x8a©ç\x94¨æ\x88·å¿«é\x80\x9fé«\x98æ\x95\x88å\x9c°æ\x90\xad建3Då®\x9eæ\x97¶æ\x95°æ\x8d®å\x8f¯è§\x86å\x8c\x96交äº\x92项ç\x9b®ã\x80\x82" /&gt;\r\n &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;\r\n &lt;meta http-equiv="X-UA-Compatible" content="IE=8"&gt;\r\n &lt;meta http-equiv="Expires" content="0"&gt;\r\n &lt;meta http-equiv="Pragma" content="no-cache"&gt;\r\n &lt;meta http-equiv="Cache-control" content="no-cache"&gt;\r\n &lt;meta http-equiv="Cache" content="no-cache"&gt;\r\n &lt;title&gt;RayData-Asset&lt;/title&gt;\r\n &lt;link rel="icon" href="/favicon.ico" type="image/x-icon"&gt;\r\n &lt;script&gt;\r\n window._czc = window._czc || [];\r\n _czc.push(["_setAccount", "1277860413"]);\r\n &lt;/script&gt;\r\n\r\n &lt;script type="text/javascript"&gt;\r\n var userAuth = function () { }\r\n\r\n // è°\x83ç\x94¨å\x90\x8eå·¥å\x85·ç«¯é\x87\x8dæ\x96°å\x8a\xa0è½½å½\x93å\x89\x8då\x9cºæ\x99¯ window.reloadWinTool()\r\n var reloadWinTool = function (){\r\n ventuz_oem.force_asset_check = true;\r\n }\r\n\r\n // è\x8e·å\x8f\x96ventuzç»\x99å\x95\x86å\x9f\x8eç\x9a\x84å\x8f\x82æ\x95°\r\n window.addEventListener("load", (evt) =&gt; {\r\n function GetUserAuth() {\r\n if (window.location.pathname.includes(\'/designer\')) {\r\n var res = ventuz_oem.is_logged_in;\r\n window.ventuz_oem = ventuz_oem;\r\n }\r\n if (res == true) {\r\n var user = ventuz_oem.raydata_user;\r\n sessionStorage.setItem(\'raydata_user\', user);\r\n }\r\n \r\n return user\r\n }\r\n userAuth = GetUserAuth();\r\n GetUserAuth();\r\n });\r\n &lt;/script&gt;\r\n&lt;link href="/index.4ea70c82.css" rel="stylesheet"&gt;&lt;/head&gt;\r\n\r\n&lt;body&gt;\r\n &lt;div id="root"&gt;&lt;/div&gt;\r\n &lt;script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"&gt;&lt;/script&gt;\r\n &lt;script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"&gt;&lt;/script&gt;\r\n &lt;!-- &lt;script src="https://www.sobot.com/chat/frame/js/entrance.js?sysNum=a047ca3c8fec47cca963d4a6e27b8706" class="zhiCustomBtn" id="zhichiScript" data-args="manual=true"&gt;&lt;/script&gt; --&gt;\r\n &lt;script src="//www.sobot.com/chat/frame/js/entrance.js?sysNum=8bd45fac5b27484da63e590fd0ff1d5e" id="zhichiScript"\r\n data-args="manual=true"&gt;&lt;/script&gt;\r\n\r\n &lt;script&gt;\r\n function getWxConfig(wxObj) {\r\n const obj = new WxLogin(wxObj);\r\n }\r\n\r\n\r\n window.onbeforeunload = function () {\r\n if (window.ws) {\r\n window.ws.close();\r\n }\r\n }\r\n\r\n // window.onload=function(){\r\n // var zhiManager = (getzhiSDKInstance());\r\n // zhiManager.on("load", function() {\r\n // zhiManager.initBtnDOM();\r\n // });\r\n // zhiManager.set(\'color\',\'3a5b8e\'); //æ\xa0¼å¼\x8f为 0-9 a-f ä¹\x8bé\x97´ç\x9a\x84å\x85\xadä½\x8dæ\x9c\x89æ\x95\x88å\xad\x97符 ä¸\x8dç\x94¨å\x8a\xa0#\r\n // zhiManager.set(\'title\',\'欢è¿\x8eå\x92¨è¯¢\');\r\n // zhiManager.set(\'location\',1);\r\n // zhiManager.set(\'horizontal\', 50);\r\n // zhiManager.set(\'vertical\', 50); \r\n // zhiManager.set(\'size\',{\r\n // \'width\':300,\r\n // \'height\':540,\r\n\r\n // });\r\n // zhiManager.set("powered", \'true\'); \r\n // zhiManager.set(\'manTrace\', true);\r\n // zhiManager.set(\'lan\', \'cn\'); //æ\x94¯æ\x8c\x81è¯\xadè¨\x80 cn ä¸\xadæ\x96\x87 en è\x8b±æ\x96\x87 é»\x98认为 ä¸\xadæ\x96\x87\r\n // zhiManager.set(\'autoExpand\',true);\r\n // zhiManager.set(\'invite\', 0);\r\n // zhiManager.set(\'isInviteFlag\',false); \r\n // zhiManager.set(\'anchor\',\'false\');\r\n // zhiManager.collapse(); \r\n\r\n // }\t\r\n\r\n var test = window.location.pathname;\r\n\r\n if (!test.includes("/invitefriends") &amp;&amp; !test.includes("/unity")) {\r\n var zhiManager = getzhiSDKInstance();\r\n zhiManager.on("load", function () {\r\n zhiManager.initBtnDOM();\r\n document.getElementById(\'zhichiBtnBox\').style.right = \'1.2rem\';\r\n });\r\n\r\n zhiManager.set(\'color\', \'3C5DEB\');\r\n zhiManager.set(\'powered\', false);\r\n }\r\n\r\n &lt;/script&gt;\r\n &lt;div style="display:none"&gt;\r\n &lt;script type="text/javascript" src="https://v1.cnzz.com/z_stat.php?id=1277860413&amp;web_id=1277860413"&gt;&lt;/script&gt;\r\n &lt;/div&gt;\r\n&lt;script type="text/javascript" src="/index.a91f0044.js"&gt;&lt;/script&gt;&lt;/body&gt;\r\n\r\n&lt;/html&gt;'
测试用例ID: 20
测试用例名称: 限制条数查询解决方案推荐
断言失败,用例名称是:限制条数查询解决方案推荐
"'msg': 'OK'" not found in '&lt;!DOCTYPE html&gt;\r\n&lt;html lang="en"&gt;\r\n\r\n&lt;head&gt;\r\n &lt;meta charset="utf-8" /&gt;\r\n &lt;meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" /&gt;\r\n &lt;meta name="renderer" content="webkit" /&gt;\r\n &lt;meta name="viewport"\r\n content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover, minimum-scale=1, user-scalable=no" /&gt;\r\n &lt;meta name="apple-mobile-web-app-capable" content="yes" /&gt;\r\n &lt;meta name="format-detection" content="telephone=no" /&gt;\r\n &lt;meta name="keywords" content="3D模å\x9e\x8bï¼\x8c3Då\x8f¯è§\x86å\x8c\x96ï¼\x8c3Dèµ\x84æº\x90å\x95\x86å\x9f\x8eï¼\x8cå\x9f\x8eå¸\x82建ç\xad\x91模å\x9e\x8bï¼\x8cå\x9b¾è¡¨ï¼\x8cå®\x9eæ\x97¶æ\x95°æ\x8d®ï¼\x8c3D设计å¸\x88ï¼\x8c3Dä½\x9cå\x93\x81å±\x95示ï¼\x8cè¡\x8cä¸\x9aè§£å\x86³æ\x96¹æ¡\x88ï¼\x8cå\x95\x86ä¸\x9aæ\x99ºè\x83½ï¼\x8cRayData Asset," /&gt;\r\n &lt;meta name="description"\r\n content="RayData Assetèµ\x84æº\x90å¹³å\x8f°æ\xad£å\x9c¨é\x80\x9aè¿\x873Då\x8f¯è§\x86å\x8c\x96ä½\x93éª\x8cæ\x94¹å\x8f\x98ä¸\x96ç\x95\x8cã\x80\x82å¹³å\x8f°æ\x8f\x90ä¾\x9bä¸\x93ä¸\x9a深度ç\x9a\x84è¡\x8cä¸\x9aè§£å\x86³æ\x96¹æ¡\x88ã\x80\x81ç²¾ç¾\x8eç\x82«é\x85·ç\x9a\x843D模å\x9e\x8bèµ\x84æº\x90ã\x80\x81æ\x96°é¢\x96å®\x9eç\x94¨ç\x9a\x84å\x9b¾è¡¨æ\xa0·å¼\x8f以å\x8f\x8aå¤\x9aæ\xa0·å\x8c\x96ç\x9a\x84ç´\xa0æ\x9d\x90帮å\x8a©ç\x94¨æ\x88·å¿«é\x80\x9fé«\x98æ\x95\x88å\x9c°æ\x90\xad建3Då®\x9eæ\x97¶æ\x95°æ\x8d®å\x8f¯è§\x86å\x8c\x96交äº\x92项ç\x9b®ã\x80\x82" /&gt;\r\n &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;\r\n &lt;meta http-equiv="X-UA-Compatible" content="IE=8"&gt;\r\n &lt;meta http-equiv="Expires" content="0"&gt;\r\n &lt;meta http-equiv="Pragma" content="no-cache"&gt;\r\n &lt;meta http-equiv="Cache-control" content="no-cache"&gt;\r\n &lt;meta http-equiv="Cache" content="no-cache"&gt;\r\n &lt;title&gt;RayData-Asset&lt;/title&gt;\r\n &lt;link rel="icon" href="/favicon.ico" type="image/x-icon"&gt;\r\n &lt;script&gt;\r\n window._czc = window._czc || [];\r\n _czc.push(["_setAccount", "1277860413"]);\r\n &lt;/script&gt;\r\n\r\n &lt;script type="text/javascript"&gt;\r\n var userAuth = function () { }\r\n\r\n // è°\x83ç\x94¨å\x90\x8eå·¥å\x85·ç«¯é\x87\x8dæ\x96°å\x8a\xa0è½½å½\x93å\x89\x8då\x9cºæ\x99¯ window.reloadWinTool()\r\n var reloadWinTool = function (){\r\n ventuz_oem.force_asset_check = true;\r\n }\r\n\r\n // è\x8e·å\x8f\x96ventuzç»\x99å\x95\x86å\x9f\x8eç\x9a\x84å\x8f\x82æ\x95°\r\n window.addEventListener("load", (evt) =&gt; {\r\n function GetUserAuth() {\r\n if (window.location.pathname.includes(\'/designer\')) {\r\n var res = ventuz_oem.is_logged_in;\r\n window.ventuz_oem = ventuz_oem;\r\n }\r\n if (res == true) {\r\n var user = ventuz_oem.raydata_user;\r\n sessionStorage.setItem(\'raydata_user\', user);\r\n }\r\n \r\n return user\r\n }\r\n userAuth = GetUserAuth();\r\n GetUserAuth();\r\n });\r\n &lt;/script&gt;\r\n&lt;link href="/index.4ea70c82.css" rel="stylesheet"&gt;&lt;/head&gt;\r\n\r\n&lt;body&gt;\r\n &lt;div id="root"&gt;&lt;/div&gt;\r\n &lt;script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"&gt;&lt;/script&gt;\r\n &lt;script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"&gt;&lt;/script&gt;\r\n &lt;!-- &lt;script src="https://www.sobot.com/chat/frame/js/entrance.js?sysNum=a047ca3c8fec47cca963d4a6e27b8706" class="zhiCustomBtn" id="zhichiScript" data-args="manual=true"&gt;&lt;/script&gt; --&gt;\r\n &lt;script src="//www.sobot.com/chat/frame/js/entrance.js?sysNum=8bd45fac5b27484da63e590fd0ff1d5e" id="zhichiScript"\r\n data-args="manual=true"&gt;&lt;/script&gt;\r\n\r\n &lt;script&gt;\r\n function getWxConfig(wxObj) {\r\n const obj = new WxLogin(wxObj);\r\n }\r\n\r\n\r\n window.onbeforeunload = function () {\r\n if (window.ws) {\r\n window.ws.close();\r\n }\r\n }\r\n\r\n // window.onload=function(){\r\n // var zhiManager = (getzhiSDKInstance());\r\n // zhiManager.on("load", function() {\r\n // zhiManager.initBtnDOM();\r\n // });\r\n // zhiManager.set(\'color\',\'3a5b8e\'); //æ\xa0¼å¼\x8f为 0-9 a-f ä¹\x8bé\x97´ç\x9a\x84å\x85\xadä½\x8dæ\x9c\x89æ\x95\x88å\xad\x97符 ä¸\x8dç\x94¨å\x8a\xa0#\r\n // zhiManager.set(\'title\',\'欢è¿\x8eå\x92¨è¯¢\');\r\n // zhiManager.set(\'location\',1);\r\n // zhiManager.set(\'horizontal\', 50);\r\n // zhiManager.set(\'vertical\', 50); \r\n // zhiManager.set(\'size\',{\r\n // \'width\':300,\r\n // \'height\':540,\r\n\r\n // });\r\n // zhiManager.set("powered", \'true\'); \r\n // zhiManager.set(\'manTrace\', true);\r\n // zhiManager.set(\'lan\', \'cn\'); //æ\x94¯æ\x8c\x81è¯\xadè¨\x80 cn ä¸\xadæ\x96\x87 en è\x8b±æ\x96\x87 é»\x98认为 ä¸\xadæ\x96\x87\r\n // zhiManager.set(\'autoExpand\',true);\r\n // zhiManager.set(\'invite\', 0);\r\n // zhiManager.set(\'isInviteFlag\',false); \r\n // zhiManager.set(\'anchor\',\'false\');\r\n // zhiManager.collapse(); \r\n\r\n // }\t\r\n\r\n var test = window.location.pathname;\r\n\r\n if (!test.includes("/invitefriends") &amp;&amp; !test.includes("/unity")) {\r\n var zhiManager = getzhiSDKInstance();\r\n zhiManager.on("load", function () {\r\n zhiManager.initBtnDOM();\r\n document.getElementById(\'zhichiBtnBox\').style.right = \'1.2rem\';\r\n });\r\n\r\n zhiManager.set(\'color\', \'3C5DEB\');\r\n zhiManager.set(\'powered\', false);\r\n }\r\n\r\n &lt;/script&gt;\r\n &lt;div style="display:none"&gt;\r\n &lt;script type="text/javascript" src="https://v1.cnzz.com/z_stat.php?id=1277860413&amp;web_id=1277860413"&gt;&lt;/script&gt;\r\n &lt;/div&gt;\r\n&lt;script type="text/javascript" src="/index.a91f0044.js"&gt;&lt;/script&gt;&lt;/body&gt;\r\n\r\n&lt;/html&gt;'
</pre>
</div>
</td>
</tr>
<tr id='total_row' class="text-center active">
<td>总计</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>通过率:100.00%</td>
</tr>
</table>
<div id='ending'> </div>
<div style=" position:fixed;right:50px; bottom:30px; width:20px; height:20px;cursor:pointer">
<a href="#"><span class="glyphicon glyphicon-eject" style = "font-size:30px;" aria-hidden="true">
</span></a></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('chart'));
// 指定图表的配置项和数据
var option = {
title : {
text: '测试执行情况',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
color: ['#95b75d', 'grey', '#b64645'],
legend: {
orient: 'vertical',
left: 'left',
data: ['通过','失败','错误']
},
series : [
{
name: '测试执行情况',
type: 'pie',
radius : '60%',
center: ['50%', '60%'],
data:[
{value:1, name:'通过'},
{value:0, name:'失败'},
{value:0, name:'错误'}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
# -*- coding: utf-8 -*-
# @Time : 2021/1/12 11:02
# @Author : wangyinghao
# @FileName: setting.py
# @Software: PyCharm
import os
from AutomatedTestPlatform.settings import BASE_DIR
EXTEND_DIR = os.path.join(BASE_DIR, "automated_main/view/api_automation/api_test_task", "extend")
# EXTEND_DIR = os.path.join(BASE_DIR, "automated_main\\view\\api_automation\\api_test_task", "extend")
TASK_RESULTS = os.path.join(EXTEND_DIR, "results.html")
print(TASK_RESULTS)
# -*- coding: utf-8 -*-
# @Time : 2021/1/27 17:01
# @Author : wangyinghao
# @FileName: test.py
# @Software: PyCharm
# -*-coding:utf-8 -*-
{"8": [{"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 114, "api_test_case_name": "callWecomSelfApi-\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/wecoms/self_dept_user_list/ww456fb5691e384999", "case_steps": 1, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 118, "api_test_case_name": "CallBackInstructController#dataPost-\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/callback/suite/data?msg_signature=5c33c5e99ee0c8db8107cd087a93d49db64a765e&timestamp=1636333277&nonce=1636030464", "case_steps": 2, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{\n\"msg_signature\":\"314dbd9c1a8d13be70b89055c728c7b503a5569e\",\n\"timestamp\":\"1636275564\",\n\"nonce\":\"1635893246\"\n\n}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 116, "api_test_case_name": "CallBackInstructController#selfPost-\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/callback/self/wwd31bf8be51d45eb1", "case_steps": 3, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{\n\"msg_signature\":\"ff222f43266f604e97e56d4eb5e7867b2507600d\",\n\"timestamp\":\"1636266865\",\n\"nonce\":\"1635949401\"\n\n}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 117, "api_test_case_name": "CallBackInstructController#suiteInstructPost-\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/callback/suite/instruct", "case_steps": 4, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 115, "api_test_case_name": "WecomApiController#callWecomApi-\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/wecoms/get_login_info", "case_steps": 5, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-wecom-api-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 119, "api_test_case_name": "CallBackInstructController#selfGet -\u65e0\u63a5\u53e3\u6587\u6863", "api_url": "https://uat.qike366.cn/api/callback/self/ww79e4f1abd45ec817?msg_signature=cf5a17aaf46d1f77c88502af07f9501222ee992d&timestamp=1636335998&nonce=1636808195&echostr=VlinnJZkAtOGCNWkKP49fb4BlMMOcBbAUYDNWeEkzwZXgJpayrxj0yb%2FIfvBDoJVIUK6L3ENW05pQ7RqA5zQ5A%3D%3D", "case_steps": 6, "dataBase_id": 1, "database_sql": ""}], "9": [{"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{\n\"urlStr\":\"https://scrm-call-1304865027.oss-cn-beijing.aliyuncs.com/production_out_15927377113_20211105141106_EV7852021030071720211105141048742.wav\"\n}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 120, "api_test_case_name": "\u6839\u636eurlStr\u4ece\u9875\u9762\u76f4\u63a5\u4e0b\u8f7d\u6587\u4ef6", "api_url": "https://uat.qike366.cn/api/chats/downLoad", "case_steps": 1, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 121, "api_test_case_name": "\u67e5\u8be2\u4f01\u4e1a\u5ba2\u6237\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/customers?size=10&name=&page=0", "case_steps": 2, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"uid\":\"uid_632231581770039296\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{\n\"size\":\"10\",\n\"quitTimeBegin\":\"\",\n\"quitTimeEnd\":\"\",\n\"name\":\"\",\n\"page\":0\n}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 124, "api_test_case_name": "\u67e5\u8be2\u79bb\u804c\u5458\u5de5\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/users/quit", "case_steps": 3, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"userId\":\"MoBai\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{\n\"size\":\"10\",\n\"departmentId\":\"11\",\n\"chatArchive\":\"\",\n\"name\":\"\",\n\"page\":0\n\n}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 123, "api_test_case_name": "\u67e5\u8be2\u5f53\u524d\u5728\u804c\u5458\u5de5\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/users", "case_steps": 4, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"name\":\"\u8881\u4f1f\u4f1f\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{\n\"userId\":\"MoBai\"\n}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 125, "api_test_case_name": "\u67e5\u8be2\u5458\u5de5\u7684\u6709\u4f1a\u8bdd\u8bb0\u5f55\u7684\u5185\u90e8\u8054\u7cfb\u4eba", "api_url": "https://uat.qike366.cn/api/chats/users/internal/contacts", "case_steps": 5, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"content\":[]", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{\n \"userIds\": [\n \"MoBai\"\n ],\n \"word\": \"\",\n \"abnormalBehaviorJudge\": 0,\n \"processed\": true\n}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 126, "api_test_case_name": "\u5185\u5bb9\u5ba1\u8ba1\u5217\u8868new", "api_url": "https://uat.qike366.cn/api/chats/audits/content/list?size=10&page=0", "case_steps": 6, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"id\":36", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 127, "api_test_case_name": "\u884c\u4e3a\u5ba1\u8ba1\u5217\u8868\u6539\u9020", "api_url": "https://uat.qike366.cn/api/chats/audits/activities/list", "case_steps": 7, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"id\":61", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 128, "api_test_case_name": "\u654f\u611f\u8bcd\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/sensitivewords/list?size=10&keyword=&page=0", "case_steps": 8, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 129, "api_test_case_name": "\u67e5\u8be2\u4f01\u4e1a\u5458\u5de5\u603b\u6570\u548c\u5f00\u542f\u4f1a\u8bdd\u5b58\u6863\u8303\u56f4\u7684\u5458\u5de5\u6570", "api_url": "https://uat.qike366.cn/api/chats/users/stat", "case_steps": 9, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"corpId\":\"ww0b5620532bd53b82\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{\"userPair\":[\"MoBai\",\"JiaWeiGang\"],\"timeType\":0,\"page\":0,\"size\":20,\"content\":\"\"}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 130, "api_test_case_name": "\u5355\u804a-", "api_url": "https://uat.qike366.cn/api/chats/o2o?types=all", "case_steps": 10, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"name\":\"\u4f01\u4e1a\u5fae\u4fe1\u7fa4\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 131, "api_test_case_name": "\u7fa4\u804a-", "api_url": "https://uat.qike366.cn/api/chats/group/list?userId=MoBai", "case_steps": 11, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "5", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 132, "api_test_case_name": "\u67e5\u8be2\u79bb\u804c\u5458\u5de5\u5b58\u6863\u6570\uff08\u5f00\u542f\u8fc7\u5b58\u6863\u7684\uff09", "api_url": "https://uat.qike366.cn/api/chats/users/quit/count", "case_steps": 12, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 1, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 133, "api_test_case_name": "\u6839\u636echat_id\u67e5\u8be2\u7fa4\u804a\u6240\u6709\u6210\u5458\u4fe1\u606f", "api_url": "https://uat.qike366.cn/api/chats/group-users?chatId=wrJfVzCwAAL0jtm3zRUrZSBnKC0Ge_Cw", "case_steps": 13, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"corpId\":\"ww0b5620532bd53b82\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 134, "api_test_case_name": "\u654f\u611f\u884c\u4e3a\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/sensitiveactivitys/list", "case_steps": 14, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"name\":\"\u542f\u5ba2\u73af\u5b87\u5ba2\u6237\u7fa4\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 135, "api_test_case_name": "\u67e5\u8be2\u5ba2\u6237\u7684\u7fa4(\u6839\u636e\u7528\u6237id,\u6216\u8005\u5ba2\u6237id)", "api_url": "https://uat.qike366.cn/api/chats/group/list?userId=MoBai", "case_steps": 15, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"msg\":\"OK\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 136, "api_test_case_name": "\u67e5\u8be2\u5ba2\u6237\u7684\u6dfb\u52a0\u4eba\u4fe1\u606f", "api_url": "https://uat.qike366.cn/api/chats/customer/contacts?externalUserid=wmSBi5CAAAJNIIkCxUXMKKhKLrDDeVdQ", "case_steps": 16, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"customerId\":\"wmU8qwDgAA6nDUs7WgxFoMV0aqTJqt-Q\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 137, "api_test_case_name": "\u6839\u636ecorpId\u548cuid\u67e5\u8be2\u5458\u5de5\u5ba2\u6237\u5217\u8868", "api_url": "https://uat.qike366.cn/api/chats/user-customers?userId=HuiYouYongDeYu", "case_steps": 17, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"name\":\"\u542f\u5ba2\u73af\u5b87\u5ba2\u6237\u7fa4\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 135, "api_test_case_name": "\u67e5\u8be2\u5ba2\u6237\u7684\u7fa4(\u6839\u636e\u7528\u6237id,\u6216\u8005\u5ba2\u6237id)", "api_url": "https://uat.qike366.cn/api/chats/group/list?userId=MoBai", "case_steps": 18, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"word\":\"\u654f\u611f\u8bcd\"", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 2, "api_parameter_body": "{\"word\":\"\u654f\u611f\u8bcd\",\"relatedWord\":\"\u654f\u611f\u8bcd\",\"id\":144}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 138, "api_test_case_name": "\u589e\u52a0/\u7f16\u8f91\u654f\u611f\u8bcd", "api_url": "https://uat.qike366.cn/api/chats/sensitivewords", "case_steps": 19, "dataBase_id": 1, "database_sql": ""}, {"api_assert_text": "\"received\":true", "api_assert_type": 1, "api_business_test_name": "xingheo-scrm-chat-prod", "api_headers": "{\"Content-Type\": \"application/json\",\n\"authorization\": \"Bearer ${Token}\"\n}", "api_method": 1, "api_parameter_body": "{}", "api_parameter_extraction": [], "api_parameter_types": 2, "api_result_id": 182, "api_task_id": 16, "api_test_case_id": 139, "api_test_case_name": "\u540c\u6b65\u5b58\u6863", "api_url": "https://uat.qike366.cn/api/chats/synchronization", "case_steps": 20, "dataBase_id": 1, "database_sql": ""}]}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment