测试开发 | 专项测试技术初识Hook

news2024/11/26 17:38:57
本文节选自霍格沃兹测试学院内部教材

Hook 技术需要预先分析目标应用的源代码和逻辑,根据目标测试场景设置目标、逻辑和数据,然后运行时动态的对目标函数参数值、逻辑或者返回值做修改,达到修改现有函数逻辑、实现目标测试场景的目的。

Hook的价值

在测试中,虽然通过修改数据以实现测试场景的需求,大部分情况下都可以通过 Mock 技术实现,但是还有一小部分场景,例如需要修改应用内部函数的参数、返回值或运行逻辑等情况,这时就需要用到 Hook 技术。

单元测试之外,Mock 技术的主要作用是对服务、接口进行 Mock,通过代理等方式将被测服务发送到依赖服务的请求转发给 Mock 服务,再由 Mock 服务根据规则组装预期的返回数据响应给被测服务,达到预期的测试场景。

Hook 技术主要用于服务内部代码逻辑上的修改,当函数间传递的参数或者函数内的逻辑需要进行修改时,数据的传递并没有经过网络,Mock 服务无法对其进行操作,只能通过 Hook 技术通过在运行的代码中插入额外的代码或者在内存中进行操作。这种更精细更底层的修改,相比 Mock 技术能实现更多的修改范围,适用性更广,难度也更大。

image801×589 26.6 KB

JVM Sandbox简介

JVM-Sandbox 是 alibaba 开源的一个 JVM 沙箱容器,只能处理目标为 Java 应用的场景,主要的特点是支持热插拔(可以在目标应用运行中随时进行 Hook 的加载和解除)、可以同时操作挂载多个目标应用,相互之间独立设置互不干扰、支持的目标应用 JDK 版本较广(6-11)。工具本身功能很多,在这里仅介绍和使用它用作 Hook 的部分功能。

JVM Sandbox安装与启动

下载

  • 项目的 github 地址:https://github.com/alibaba/jvm-sandbox。 1

  • 下载所需版本的二进制压缩包,解压(演示所使用的版本为 1.3.3)。

环境准备

  • 官方声明支持的系统有:Linux/UNIX/MacOS,这几个系统只需要下载解压缩就可以直接运行。

  • 官方并未支持 Windows 系统,所以需要进行如下修改:

  • 安装 Git Bash。

  • 安装 JDK(版本 6-11,演示所用版本为 1.8.0_192),路径中不能带有空格。

  • 在 Shell 脚本中会有 Java 命令的调用,所以电脑中需要,并且因为 Git Bash 运行 Shell 脚本时的目录问题。

  • 修改启动脚本bin/sandbox.sh ,将脚本中 183-188 行内容注释。

image1080×277 95.5 KB

启动脚本

  • 由于启动脚本中使用了相对路径,所以运行时需要切换到项目的 bin 目录下操作。

  • 在 bin 目录中执行语句./sandbox.sh -p 目标应用pid ,当出现如下提示信息,说明 JVM-Sandbox 已经成功启动了。

$ ./sandbox.sh -p 6204

NAMESPACE : default

VERSION : 1.3.3

MODE : ATTACH

SERVER_ADDR : 0.0.0.0

SERVER_PORT : 4543

UNSAFE_SUPPORT : ENABLE

SANDBOX_HOME : e:/Download/sandbox/bin/..

SYSTEM_MODULE_LIB : e:/Download/sandbox/bin/..\module

USER_MODULE_LIB : E:\Download\sandbox\sandbox-module;~/.sandbox-module;

SYSTEM_PROVIDER_LIB : e:/Download/sandbox/bin/..\provider

EVENT_POOL_SUPPORT : DISABLE

  • JVM-Sandbox 同时还会对外提供接口,可以通过请求直接操作 JVM-Sandbox,这样就能方便的与自己的测试代码结合使用。

JVM Sandbox示例

  • 目标应用为一段简单的 Java 代码,代码中启动了一个死循环,每次循环会打印report 方法接收到的参数值,参数值已经在代码中固定传入,所以运行之后的结果是一串相同的输出内容。具体内容如下:

public class HookTarget { final void report(String stringParam, boolean boolParam, int intParam) {

System.out.println("stringParam is " + stringParam); if (boolParam) {

System.out.println("boolParam is true!");

} else {

System.out.println("boolParam is false");

}

System.out.println("intParam is " + intParam);

} final void loopReport() throws InterruptedException { while (true) {

report("a", false, 666);

Thread.sleep(1000);

System.out.println();

}

} public static void main(String... args) throws InterruptedException { new HookTarget().loopReport();

}

}

  • 要编写符合 JVM-Sandbox 的 hook 脚本,需要引入sandbox-api 和 sandbox-debug-module 两个依赖。

  • 通过实现 jvm.sandbox 中的 Module 接口,在 AdviceListener 方法中重写 before 方法,这样写入的语句就会在目标方法体执行之前进行执行,能够修改目标方法收到的参数数据。通过advice.changeParameter 方法,修改对应位置的参数数值,第一个参数为目标参数的位置,从 0 开始,第二个参数为替换的值。具体代码如下:

import com.alibaba.jvm.sandbox.api.Information;import com.alibaba.jvm.sandbox.api.Module;import com.alibaba.jvm.sandbox.api.annotation.Command;import com.alibaba.jvm.sandbox.api.listener.ext.Advice;import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener;import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder;import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher;import org.kohsuke.MetaInfServices;import javax.annotation.Resource;import java.util.*;@MetaInfServices(Module.class)@Information(id = "ceshiren.com", author = "ceshiren.com")public class hook_jvm implements Module { @Resource

private ModuleEventWatcher moduleEventWatcher; @Command("ceshiren")

public void ceshiren(final Map<String, String> param) { new EventWatchBuilder(moduleEventWatcher)

.onClass("HookTarget")

.onBehavior("report")

.onWatch(new AdviceListener() { @Override

protected void before(Advice advice) throws Throwable {

advice.changeParameter(0, "Change By Hook!");

advice.changeParameter(1, false);

advice.changeParameter(2, 965);

}

});

}

}

  • 项目通过 maven 管理依赖,对应的pom.xml 文件内容如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 " target="_blank">http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>

<artifactId>ceshiren_book</artifactId>

<version>1.0-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>com.alibaba.jvm.sandbox</groupId>

<artifactId>sandbox-api</artifactId>

<version>1.3.3</version>

</dependency>

<dependency>

<groupId>com.alibaba.jvm.sandbox</groupId>

<artifactId>sandbox-debug-module</artifactId>

<version>1.3.3</version>

<scope>compile</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-assembly-plugin</artifactId>

<executions>

<execution>

<goals>

<goal>attached</goal>

</goals>

<phase>package</phase>

<configuration>

<descriptorRefs>

<descriptorRef>jar-with-dependencies</descriptorRef>

</descriptorRefs>

</configuration>

</execution>

</executions>

</plugin>

</plugins>

</build></project>

  • 脚本编写完毕之后,将项目打成 Jar 包,放到下载的 JVM-Sandbox 项目下 sandbox-module 目录中。

  • 启动写好的 java 目标程序,运行之后命令行开始循环打印之前设置好的语句,内容如下:

stringParam is a

boolParam is falseintParam is 666stringParam is a

boolParam is falseintParam is 666

  • 在 gitbash 命令行中打开sandbox/bin 目录,执行语句./sandbox.sh -p 目标应用进程号 -d 'ceshiren.com/ceshiren' ,启动 JVM-Sandbox 并对目标程序进行 Hook 操作,变更report 方法中传入的参数值,这时再回到目标程序运行的命令行中查看,可以看到命令行中输出的内容已经变更,如下:

stringParam is Change By Hook!

boolParam is falseintParam is 965stringParam is Change By Hook!

boolParam is falseintParam is 965

  • 输出内容的变更,说明 Hook 已经生效。这样在目标程序运行中修改了方法传入的参数值,达到了 Hook 的目的。

  • 现在执行语句./sandbox.sh -p 目标应用进程号 -S 可以关闭修改,命令行中输出的内容变回了原始的输出内容。

示例简单展示了 JVM-Sandbox 用作 Hook 工具的功能,通过 Hook 功能就可以对 Java 项目的内部运行逻辑和参数、返回值进行修改。测试场景的构建、测试用例的执行都变得更加方便哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb基础(一) Mybatis使用详解

JavaWeb基础——Mybatis 1&#xff0c;配置文件实现CRUD 如上图所示产品原型&#xff0c;里面包含了品牌数据的 查询 、按条件查询、添加、删除、批量删除、修改 等功能&#xff0c;而这些功能其实就是对数据库表中的数据进行CRUD操作。接下来我们就使用Mybatis完成品牌数据的…

3-2存储系统-主存与CPU的连接外部存储器

文章目录一.主存与CPU的连接&#xff08;一&#xff09;连接原理&#xff08;二&#xff09;主存容量的扩展1.位扩展法2.字扩展法3.字位同时扩展法&#xff08;三&#xff09;存储芯片的地址分配和片选1.线选法2.译码片选法二.外部存储器&#xff08;一&#xff09;磁盘储存器1…

JVM-三色标记

一、什么叫三色标记三色也叫三色抽象&#xff0c;它是所有mutator和collector都必须遵守的定律。它把对象标记为三种颜色&#xff1a;白色&#xff1a;对象还未被垃圾收集器访问&#xff0c;在回收的开始阶段所有的对象均为白色&#xff08;当然了这只是指概念上的&#xff0c;…

PaddleNLP开源UTC通用文本分类技术,斩获ZeroCLUE、FewCLUE双榜第一

飞桨PaddlePaddle 2023-01-12 20:02 发表于湖北 针对产业级分类场景中任务多样、数据稀缺、标签迁移难度大等挑战&#xff0c;百度提出了一个大一统的通用文本分类技术UTC&#xff08;Universal Text Classfication&#xff09;。 UTC在ZeroCLUE和FewCLUE两个榜单上均位居榜首…

css加载会造成阻塞吗?

目录 A.设置网络加载速度 B.css加载会阻塞DOM树的解析渲染吗&#xff1f; 1.css会阻塞DOM树解析&#xff1f; 2.css加载会阻塞DOM树渲染&#xff1f; 3.个人对这种机制的评价 3.css加载会阻塞js运行吗&#xff1f; 4.结论 可以使用以下几种方法解决CSS加载速度的问题: …

曲线曲率介绍和python求法

目录曲率1.1 弧长参数 s参考资料曲率 比如我们想知道曲线 AB\boldsymbol{AB}AB 上任一点处的弯曲程度怎么办呢&#xff1f;这时就需要一个十分重要的概念——曲率。 维基百科&#xff1a; 在数学中&#xff0c;曲率&#xff08;curvature&#xff09;是描述几何体弯曲程度的量…

Octave安装与使用

1. 介绍 Octave是一种编程语言&#xff0c;旨在解决线性和非线性的数值计算问题。Octave为GNU项目下的开源软件&#xff0c;早期版本为命令行交互方式&#xff0c;4.0.0版本发布基于QT编写的GUI交互界面。Octave语法与Matlab语法非常接近&#xff0c;可以很容易的将matlab程序…

机器学习/人工智能 实验二:图像特征自动学习方法实践与分析

写在前面 参考的是https://zh.d2l.ai/index.html 一、实验目的与要求 (1)利用基于深度学习的特征自动学习方法完成图像特征提取的实验方案的设计。 (2)编程并利用相关软件完成实验测试&#xff0c;得到实验结果。 (3)通过对实验数据的分析、整理&#xff0c;得出实验结论&am…

Unity | 序列化(Serialized)和反序列化(NonSerialized)是什么意思

一、什么是序列化 官方叙述&#xff1a;序列化是将对象的状态信息转换为可以存储或传输的形式的过程。 人话叙述&#xff1a;我们平时输入的代码&#xff0c;实际上是不能储存或者传输的&#xff0c;所以我们需要翻译一下&#xff0c;翻译成能储存或者翻译的文字&#xff0c;这…

【SpringBoot 学习】52、SpringBoot 使用 grpc 实现远程服务调用

文章目录一、SpringBoot 使用 grpc 实现远程服务调用1、服务端编写2、客户端编写一、SpringBoot 使用 grpc 实现远程服务调用 gRPC 是一个现代的、开源的、高性能的远程过程调用&#xff08;RPC&#xff09;框架&#xff0c;可以在任何地方运行。gRPC 使客户端和服务器应用程序…

Java-Thread多线程的使用

Java-Thread多线程的使用一、线程&#xff0c;进程&#xff0c;并发&#xff0c;并行的概念1.进程2.线程3.并发和并行二、线程的创建和使用1.通过继承Thread类&#xff0c;重写run方法2.实现Runnable接口&#xff0c;重写run方法3.使用案例三、线程的常用方法四、线程的退出和中…

关于机器人状态估计(11)-VIO单目与双目/雷达Lidar SLAM/未来的机器人

写这篇文章的时候刚发生行业大事件&#xff1a; Google收购ROS 其实一开始还是水&#xff0c;绝对大量文不对题&#xff0c;但是必有干货&#xff0c;毕竟用的是这个关键的系列标题。 最近有几件行业内发生的大小事&#xff0c;让我觉得有必要更一下。 首先是Livox的mid-360…

VueUse(中文)——核心函数:State相关函数

VueUse官方地址 一、createGlobalState 将状态保持在全局范围内&#xff0c;以便跨Vue实例重用 1、没有持久性(存储在内存中) 例如&#xff1a; 或者 2、持久性存储 使用useStorage()存储在localStorage:例如&#xff1a; 组件使用&#xff1a; 二、createInjectionSt…

【图灵商城】前、后端项目搭建与运行

【图灵商城】前、后端项目搭建与运行 项目介绍 图灵商城-基础班架构图&#xff0c;如下所示&#xff1a; 本节是项目代码的初始化&#xff0c;今天是2023-01-15&#xff0c;先预祝大家新年快乐&#xff01;&#xff01;&#xff01; 图灵商城这个项目是一个前后端分离的项目…

我这是这样知道 React TS 中的 Event Handler 类型的

开头 现在 TypeScript 的发展也越来越成熟&#xff0c;已逐渐应用到我们开发的前端项目之中&#xff0c;它能够带来类型提示&#xff0c;提前规避类型上的错误&#xff0c;来提高项目代码的健壮性&#xff0c;以及更高效的编码效率&#xff0c;前提就是我们需要定义好相应的类…

创客匠人赋能线上瑜伽健身实现流量增长

近年来&#xff0c;我国的儿童、成年人肥胖率逐年攀升。身边发胖的人越来越多&#xff0c;尤其是步入中年的人群&#xff0c;很多都有“发福”的现象。 超重肥胖已经成为影响我国居民健康的重要公共卫生问题。在身材焦虑和疫情肆虐下&#xff0c;很多人开始重视自己的健康问题…

python学习笔记---Python基础【廖雪峰】

Python基础 数据类型和变量 整数 对于很大的数&#xff0c;例如10000000000&#xff0c;很难数清楚0的个数。Python允许在数字中间以_分隔&#xff0c;因此&#xff0c;写成10_000_000_000和10000000000是完全一样的。十六进制数也可以写成0xa1b2_c3d4。 >>> prin…

Qt opencv编译详细教程(windows版)

在Qt中使用opencv这个算法视觉库&#xff0c;前期环境步骤搭建如下&#xff1a; 1、下载cmake。 2、下载opencv库&#xff0c;我这里下载的是opencv-3.3.1版本。 3、没有安装Qt的下载Qt软件&#xff0c;Qt的环境安装部署&#xff0c;这里不做介绍。 4、安装cmake后&#xff0c;…

python学习笔记---IO编程【廖雪峰】

IO编程 ​ IO在计算机中指Input/Output&#xff0c;也就是输入和输出。由于程序和运行时数据是在内存中驻留&#xff0c;由CPU这个超快的计算核心来执行&#xff0c;涉及到数据交换的地方&#xff0c;通常是磁盘、网络等&#xff0c;就需要IO接口。 ​ IO编程中&#xff0c;S…

冒泡排序算法的实现和优化~

冒泡排序算法&#xff1a; 算法思想&#xff1a; 反复扫描待排序记录序列&#xff0c;在扫描的过程中&#xff0c;顺次比较相邻的两个元素的大小&#xff0c;若逆序就交换位置 文字描述该算法&#xff1a; 以升序为例&#xff1a; 依次比较数组中相邻两个元素大小&#xf…