为什么要这么做?
任何项目开发都是有周期的。开发工作和测试工作总是交叉迭代进行的,作为开发人员,猿Why希望工作当中尽可能少干体力活、手工活,有效利用前期的工作成功,提升工作效率。
作为开发人员,在交付接口之前一定会进行测试覆盖。开发时候测试、交给测试同学测试、交给前端同学联调测试。而我想达到一个目标:交付接口的时候,带着文档,这一份文档从需求确定、到开发过程、到测试过程、到交付需求都是完整可读的。
猿Why当前参与的项目已经到了测试阶段,奈何资源不足,没有匹配专业的测试同学进行测试工作。所以要求开发的同学们将项目中的接口,写JMeter测试计划,目的是用于“接口验证(测试)”,甚至是压力测试使用。但是正如猿Why前面说的:“少干体力活、手工活”。出于降低工作重复性、避免“开发人员不可信”,所以就想遵循一个标准,通过工具生成JMeter测试计划的脚本。
思路
JMeter测试计划脚本是XML格式文件,这为猿Why的计划提供了可行性idea。查阅资料之后,看到了Fiddler可以抓包导出JMeter计划,在[JMeter系列]利用Fiddler生成JMeter脚本中进行了实践验证。
所以,只要有一个match的数据结构,就可以生成脚本。那么接口数据如何得来?
想法1:扫描注解生成
在MVC的项目中,定制代码扫描插件,扫描代码(类文件)中的@Controller、@RequestMapping注解,读取注解中的信息,生成接口文档。
在实践过程中发现该方法可行性不大:
1)类文件扫描,需要对类加载器异常,jar依赖不好处理
2)如果在Controller层用到Spring AOP,几乎无法获取目标类中的基本信息(cglib增强生成了新的类)
想法2:基于Swagger接口文档
猿Why的项目中,集成了Swagger。前后端分离模式下,Swagger交由前端同学使用。基于这个前提工作,也符合猿Why前面说的“降低工作重复性”。
简单跟踪了Swagger接口文档请求之后,发现拿到接口文档数据异常简单。(Swagger不在此做深入介绍)
@ApiIgnore @RestController @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)@RequestMapping(SWAGGER2_SPECIFICATION_PATH)@Conditional(OnServletBasedWebApplication.class)@Order(Ordered.HIGHEST_PRECEDENCE) public class Swagger2ControllerWebMvc { public static final String SWAGGER2_SPECIFICATION_PATH = "${springfox.documentation.swagger.v2.path:/v2/api-docs}"; private static final Logger LOGGER = LoggerFactory.getLogger(Swagger2ControllerWebMvc.class); private static final String HAL_MEDIA_TYPE = "application/hal+json"; private final DocumentationCache documentationCache; private final ServiceModelToSwagger2Mapper mapper; private final JsonSerializer jsonSerializer; private final PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations; @Autowired public Swagger2ControllerWebMvc(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer, @Qualifier("webMvcSwaggerTransformationFilterRegistry")PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations) { this.documentationCache = documentationCache; this.mapper = mapper; this.jsonSerializer = jsonSerializer; this.transformations = transformations; } @RequestMapping(method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE}) public ResponseEntity<Json> getDocumentation( @RequestParam(value = "group", required = false) String swaggerGroup, HttpServletRequest servletRequest) { String groupName = ofNullable(swaggerGroup).orElse(Docket.DEFAULT_GROUP_NAME); Documentation documentation = documentationCache.documentationByGroup(groupName); if (documentation == null) { LOGGER.warn("Unable to find specification for group {}", groupName); return new ResponseEntity<>(HttpStatus.NOT_FOUND); } Swagger swagger = mapper.mapDocumentation(documentation); SwaggerTransformationContext<HttpServletRequest> context = new SwaggerTransformationContext<>(swagger, servletRequest); List<WebMvcSwaggerTransformationFilter> filters = transformations.getPluginsFor(DocumentationType.SWAGGER_2); for (WebMvcSwaggerTransformationFilter each : filters) { context = context.next(each.transform(context)); } return new ResponseEntity<>(jsonSerializer.toJson(context.getSpecification()), HttpStatus.OK); } } |
代码实现
实现分为三步:
· 获取Swagger接口文档列表
· 接口文档转换为测试计划Session数据结构
· 测试计划Session列表脚本输出
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理