java开发接口自动化测试jar包(初步)

本文介绍了一种使用Java开发的接口自动化测试Jar包,通过切面技术和字节码操作,实现对特定类的增强,自动收集测试用例并上传至测试网站,大幅减少人工录入工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java开发接口自动化测试jar包(初步)


文章仅仅是提供了一个初步的实现方式和思路,还有很多地方要完善。

项目信息

项目目标:在开发者无需关心的情况下,使用切面技术,对特定类进行增强,,最终将拦截到的数据上传到指定测试网站上。可以收集每次的测试用例,从而大大减少了人工录入的时间。

技术选型:asm字节码操作框架(core api) + httpClient 网络请求框架, jdk 1.8+ ,spring 4.x+

项目架构:maven非web项目,最终会打包为一个jar

选用理由: 虽然asm开发上有一定难度,但开发完成后使用简单,配置正确后启动即可。而且以后可以利用同种思想,对service或者dao进行拦截,来完成某些用例收集需求。

下载地址见文章尾部

平台网址

yapi_cvte

yapi官方网址

yapi使用文档

成果展示

使用前

目标平台

plantform_empty

接口列表(测试前)

这里写图片描述

测试集合列表(测试前)

这里写图片描述

使用本jar代理启动目标jar

这里写图片描述

启动postman

这里写图片描述

结果

可以观察每个接口的详细数据都被录入了,与postman信息一致

这里写图片描述

详细信息也是

这里写图片描述

测试集合也是一样,与接口是一对多的关系

这里写图片描述

这边是测试接口的界面.可以看见数据也是成功录入的
这里写图片描述

增强的字节码内容

植入后的字节码文件:

增强Controller:

@PostMapping({"{roomCode}/join"})
    public Response connectRoom(@PathVariable("roomCode") String roomCode, @RequestHeader("systemId") String systemId, HttpServletRequest request) {
        if(ObjectUtils.isEmpty(roomCode)) {
            throw new ServiceException("roomCode不能为空", Integer.valueOf(ErrorStatus.PARAMS_NOT_MATCHED.getCode()));
        } else {
            RoomConnectRequestVo roomConnect = new RoomConnectRequestVo();
            inputValueFromReq(roomConnect, request);
            roomConnect.setRoomCode(roomCode);
            roomConnect.setSystemId(systemId);
            Response var10000 = this.connectionService.joinRoom(roomConnect);
            
            //====================增强部分
            String var6 = "ConnectController.connectRoom";
            ArrayList var8 = new ArrayList();
            var8.add("POST");
            ArrayList var10 = new ArrayList();
            StringBuffer var12 = new StringBuffer();
		   var10.add(var12.append("/roomcenter/rooms").
            .append("/").append(roomCode).append("/join").toString());
            HashMap var14 = new HashMap();
            var14.put("systemId", systemId);
            ControllerWeavingUtils.doMock(var10000, var6, var8, var10, (HashMap)null, (Object)null, request, var14);
            //====================增强部分
            
            return var10000;
        }
}

添加Interceptor:

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
    //====================增强部分
    public HandlerInterceptorAdapter getWeavingHandler_() {
        MyClassLoader myClassLoader = new MyClassLoader();
        try {
            Class<?> UploadInterceptor = myClassLoader.loadClass("UploadInterceptor");
            Object o = UploadInterceptor.newInstance();
            if(o instanceof HandlerInterceptorAdapter) {
                HandlerInterceptorAdapter weavingHandler = (HandlerInterceptorAdapter)UploadInterceptor.newInstance();
                System.out.println(o);
                return weavingHandler;
            }
        } catch (Exception var4) {
            var4.printStackTrace();
        }

        System.out.println("拦截器加载异常.......");
        return null;
    }
   //====================增强部分
    public InterceptorConfig() {
    }


    public void addInterceptors(InterceptorRegistry registry) {
        //====================增强部分
        registry.addInterceptor(this.getWeavingHandler_()).addPathPatterns(new String[]{"/**"});
        //====================增强部分
        InterceptorRegistration registration = registry.addInterceptor(this.getTokenHandler());
        registration.addPathPatterns(new String[]{"/roomcenter/**"});
        super.addInterceptors(registry);
    }
    
    @Bean
    public TokenHandlerInterceptorAdapter getTokenHandler() {
        return new TokenHandlerInterceptorAdapter();
    }
    //...
}

增强ControllerAdvice

@ControllerAdvice
public class GlobalExceptionHandler implements ResponseBodyAdvice {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    //====================增强部分
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        System.out.println("-----------------------我是拦截-------------------------");
        return true;
    }

    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        ServletServerHttpRequest sshr = (ServletServerHttpRequest)serverHttpRequest;
        HttpServletRequest request = sshr.getServletRequest();
        ConAdviceWeavingUtils.doMock(request, o, methodParameter, mediaType);
        return o;
    }
    //====================增强部分
    public GlobalExceptionHandler() {
    }

    @ExceptionHandler({ServiceException.class})
    @ResponseBody
    public Response serviceException(ServiceException exception) {
        log.error("code = {}, message = {}", exception.getCode(), exception.getMessage());
        return Response.error(exception);
    }
	//...
}

执行流程图:

这里不支持mermaid格式流程图,所以显示不出来了,有需要的人可以在别的md编辑器上打开查看

asm相关部分

代理模式启动流程图
init Conifg&Http
choose aspect
controller
interceptor
conadvice
Config.isGenClassToDisk
Config.isGenClassToDisk
Config.isGenClassToDisk
MyAgent.premain
ClassTransformer.transrom
ClassScanner.classScanner
Config.enhanceType
controllerScanner
interceptorScanner
conAdviceScanner
ControllerAdapter
InterceptorAdapter
ConAdviceAdapter
ClassScanner.writeToClass
ControllerAdapter or ConAdviceAdapter

以下全为ControllerAdapter举例

类增强的流程图
isController
not
多次
isController
isControllerMethod
isControllerMethod
aspect.before
not
aspect.after
visitAnnotation
ControllerClassAnoAdapter
default
访问类注解....
visit
visitMethod
ControllerMethodAdapter
visitMethodAnnotation
ControllerMethodAnoAdapter
defalut
onMethodEnter
onMethodExit
default
Method:visitEnd
Class:visitEnd
aspect的asm操作流程图

其中getInsertPosList()为获取之前所有的插入的局部变量在局部变量表中的位置

什么也没执行
opcode == ATHROW
opcode == RETURN
ohter
ACONST_NULL
DUP
获取doMock方法的方法描述符
压入所有的参数到操作数栈中
插入doMock方法
aspect.before
aspect.after
不做处理
函数没有返回值,正常情况下不可能
正常情况
weaving
分析weaving函数
getMethodType
getInsertPosList
visitMethodInsn
增强后的Controller执行流程图
判断上传方式
构建上传对象
进行上传
xxxController.xxxMethod
构造一系列参数...
ControllerWeavingUtils.doMock
分析doMock函数
chooseUploadType
getEditObject
upload
InterceptorAdapter
拦截器增强的流程图

InterceptorAdapter

isExtends
not
添加一个拦截器
isAddInterceptors
not
aspect.before
visit
aspect.getBeanMethod
default
visitMethod
InterceptorMethodAdapter
default
onMethodEnter
Method:visitEnd
Class:visitEnd
aspect 的asm操作流程图

不复杂,略

增强后的Interceptor执行流程图
获取拦截器
注册拦截器
class xx: WebMvcConfigurerAdapter
getWeavingHandler_ 注:这里使用的类加载器方式加载
addInterceptors
registry.addInterceptor
main方式启动流程图(开发)

我们在开发时,要手动扫描类文件,即ClassTools.getClasses

init Conifg&Http
choose aspect
controller
interceptor
conadvice
is target?
is target?
is target?
Main
Main.testAsm
ClassTools.getClasses
ClassScanner.genEnhanceClasses
Config.enhanceType
enhanceController
enhanceInterceptor
enhanceControllerAdvice
ControllerAdapter
InterceptorAdapter
ConAdviceAdapter
ClassScanner.writeToClass
Config.init()

即读取配置文件,并按照一定规则进行读取

Config.scanConf
Config.weavingConf
Config.plantformConf
Config.devConf

其他

http相关部分

http.getHttpClient()

初始化HttpClient,并缓存数据

isCookieExits
not
缓存数据,设置id值
getHttpClient
HttpClients.build
login
afterLogin
updateXXX
http.uploadCase()
isInterFaceExsit
not
获得接口id
获得接口id
isTestCaseExsit
not
获取Id
uploadCase
getIdInCache
addInterFace_添加
editInterFace_编辑
updateInterfaces_缓存
get id
return null
testCases.add_缓存
addTestCase_添加
findAllTestCase
editTestCase_编辑
return JsonObj

项目git地址: 觉得有用就点个星星吧

参考链接:

-[asm官网]: http://asm.ow2.org/ “asm框架地址”
-[asm4中文指南]: http://www.jb51.net/books/488919.html “asm国内最高版本的翻译”
-[jvm指令集]: https://blog.youkuaiyun.com/sum_rain/article/details/39892219 “指令大全”
-[asm实现aop]: https://my.oschina.net/u/3269106/blog/1154508 “难得的原创不是抄自中文指南里的博客”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值