AspectJ在测试中的应用

简介:

1. 介绍
1.1面向切面的编程
面向切面的编程(AOP,Aspect Oriented Programming),主要实现的目的是针对业务处理过程中的切面进行提取,它所面对是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。
软件设计的一个重要原则,就是要清晰分离各种关注点,然后分而治之,各个击破,最后形成同一的解决方案。然而在目前的技术框架下,通常系统级关注点在逻辑上相互独立,在实现上趋向于和若干核心模块交织。就如下图所示,业务逻辑和安全,日志,一致性交织在了一块,源程序变成一些为不同目的而编写在一起的混乱物。
 



AOP专为关注点而生,其目标使设计和代码更加模块化、更具结构性,使关注点局部化而不是分散在整个系统中,同时和系统其它部分保持良好定义的接口,从而真正达到不仅在设计上分离,实现上也分离的目的。AOP被认为是后面向对象时代的一种新的重要的程序设计技术。
 




1.2 AspectJ
AspectJ是一个面向切面编程的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
编织(weave),是将核心关注点和横切关注点有机融合的过程。其中,核心关关注点表示业务功能和业务逻辑,横切关注点表示业务功能的功能约束。AspectJ目前支持以下三种编织的方式:
※ 编译时编织(compile-time weaving):在编译的过程中进行编织
※ 编译后编织(post-compile weaving):对已经编译好的字节码进行编织
※ 加载时编织(load-time weaving):在类被加载进JVM的时候进行编织,在加载时通过aop.xml对编织的对象进行控制

AspectJ中引入下列这些概念
连接点(Join Point):程序执行过程中明确定义的可以被识别的点或位置。
切入点(Pointcut):连接点的集合,通过连接点标识明确定义需要收集的连接点和有关参数值,它是联系方面和类的桥梁。比如:
pointcut callSetter( ): call (public void HelloWorld.set*(..))
其中:
pointcut说明声明的是一个切入点,命名 callSetter,后面的空括号表示该切入点不需要上下文信息。 
call表示该切入点捕获的是对指定方法的调用,指定的方法是在类HelloWorld中声明的公有的、返回值为空、以set开头、拥有任意参数的方法。
通知(Advice):在符合特定条件的情况下执行具体动作的代码的语言构造子称为通知,即声明在连接点被调用时应该执行的动作。依据切入点的语义,将通知分为以下三类:
※ Before advice:在连接点之前执行;
※ After advice :在连接点之后执行;
※ Around advice :代替原连接点处方法的执行。
方面(Aspect):一个方面是封装横切关注点的一个独立的标准单元,类似于面向对象编程中的类。其中包括通知和切入点的定义。

以下是一个简单的例子,例如有一个类HelloWorld, 
public class HelloWorld {
public void sayHello() {
System.out.println("Hello, world!");
}

public static void main(String[] argv) {
HelloWorld hw = new HelloWorld();
hw.sayHello();
}
}

现在想在sayHello方法被调用之前和之后多打印一行输出,可编写如下的代码
public aspect SayAspect {
pointcut say():call(void HelloWorld.sayHello());

before():say() {
System.out.println("before say hello....");
}
after():say() {
System.out.println("after say hello....");
}


也可以采用标记的方法编写
@Aspect
public class SayAspect {
@Pointcut(“execution(void HelloWorld.sayHello())”)
public void say() {}

@Before(“say()”)
public before(){
System.out.println("before say hello....");
}

@After(“say()”)
public after(){
System.out.println("after say hello....");
}


2. 在测试中的使用
2.1测试需求
在测试中测试人员需要构造各种各样的测试场景。但是在一些系统中,特别是在一个复杂的系统中,一些测试场景不能够容易地被创建,比如:
※ 随机性事件,比如需要测试条件A下,程序分别在条件B和条件C下的运行情况。但由于产生条件A在程序中是随机的,测试人员要么需要修改代码,要么只能重复地执行这个用例,直到程序产生条件A为止;
※ 异常,通常测试人员需要求助于不同的第三方的工具来模拟不同的异常,另外有时异常的触发不够直接,时机不好掌握;
※ 复杂的流程,一些bug在特定的交互时序下才会实现,而特定的时序从程序外部无法控制,这时测试人员只有改动程序的代码才能重现。

这里以HDFS中的写流程为例,讲讲在测试过程中遇到的一些问题。下图是一个典型的客户端写3副本的流程。
 




首先,在测试中需要构造异常在第一个DataNode触发,中间DataNode触发和最后一个DataNode触发的情况。但是,每次客户端构造pipeline中的3个DataNode的顺序是随机的。
其次,目前异常的触发是通过apihook来进行,apihook可以在写指定文件和接收发送来自指定端口的消息时产生异常。但是就如上图所示,create和stream时用的是同一个socket,但是apihook无法区分create和stream过程。
2.2使用AspectJ进行测试
对于测试而言,AspectJ为测试人员提供了一种注入代码的方法,从而可以在不改变原有代码的情况下,对指定方法的行为进行控制,更方便地构造出测试人员想要的场景。并且可以不依赖于其它的工具。
下面我们来看看如何使用AspectJ来解决2.1中提到的hdfs写流程问题,在这里采用加载时编织的方式。
1. 首先根据2.1中提到的问题,编写三个Asepct,然后编译并打成一个jar包,如inject.jar

OrderAspect.java 在Client从NameNode获取到DataNode时,对这些DataNode依据机器名进行重排序
public aspect OrderAspect {
pointcut order():call(* DFSClient.DFSOutputStream.locateFollowingBlock(..));

LocatedBlock around():order() {
LocatedBlock locateBlock = proceed();
/* DataNode的信息存在loacteBlock中,在此进行重排序 */
return locateBlock;
}
}

CreateAspect.java在创建pipeline的时候抛出IOException异常
public aspect CreateAspect {
pointcut pipeline():call(* DataXceiver.writeBlock(..));

before() throws IOException :pipeline() {
throw new IOException("by aspectj");
}
}

StreamAspect.java在传输数据的时候抛出IOException异常
public aspect StreamAspect {
pointcut write():call( * BlockReceiver.receivePacket());

after() throws IOException : write() {
throw new IOException("by aspectj");
}
}

2. 之后就可以通过更改对应结点的aop.xml的配置来控制要注入的代码。例如,现在想测试当中间的DataNode在传输数据的过程中抛出异常的情况,对应结点的aop.xml可以如下图配置。由于通过OrderAspect在建立pipeline之前对DataNode进行了排序,因此我们可以明确哪个DataNode处于pipeline中间的位置。配置好好重启集群,配置项就可以生效了。
 


3. 在hadoop中,我们可以采取类似的方法使用AsepctJ进行测试。
a) 平常我们可以把对应的测试中要注入的代码合到项目中,在编译整个项目时,这些注入的代码都被打包到一个jar包中,比如hadoop-2-inject.jar。
b) 在执行一个测试用例前,根据测试的需要配置aop.xml(使用加载时编织的方法)控制要注入的代码,并发送到相应的节点上,然后启动集群进行测试。

由于每个测试流程都是一样的,修改aop.xml,分发到对应结点上,启动集群,测试,所以也可以方便的自动化。
apihook是通过一种间接的方式触发我们需要的代码逻辑,而AspectJ提供了一种更直接、方便的方法控制代码逻辑。

3. 使用指南
这里以1.2中HelloWorld为例子,介绍如何使用AspectJ
首先从http://www.eclipse.org/aspectj/下载最新的jar包,并进行解包,并设置变量
ASPECT_LIB =”解包路径/lib”
3.1编译时编织
如果采用编译时编织的方法,则使用以下命令进行编译
java –classpath $ASPECT_LIB/aspectjrt.jar:$ASPECT_LIB/aspectjtools.jar:$CLASSPATH org.aspectj.tools.ajc.Main *.java

运行的时候用如下命令:
java –classpath $ASPECT_LIB/aspectjrt.jar:$CLASSPATH HelloWorld

3.2加载时编织
如果采用加载时编织的方法,首先对HelloWorld.java进行编译
Javac HelloWorld.java
然后对SayAspect.java进行编译,并输出一个aop.xml的文件
java –classpath $ASPECT_LIB/aspectjrt.jar:$ASPECT_LIB/aspectjtools.jar:$CLASSPATH org.aspectj.tools.ajc.Main –outxml SayAspect.java
执行完成后可以看到当前目录下新生成了一个META-INF目录,目录中有一个aop-ajc.xml文件,该文件供编织时使用。

运行的时候用如下命令:
java –classpath $ASPECT_LIB/aspectjrt.jar:$CLASSPATH -javaagent:$ASPECT_LIB/aspectjweaver.jar HelloWorld

 (作者:pyjin)

 












本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/744424,如需转载请自行联系原作者

相关文章
|
4月前
|
监控 安全 Shell
管道符在渗透测试与网络安全中的全面应用指南
管道符是渗透测试与网络安全中的关键工具,既可用于高效系统管理,也可能被攻击者利用实施命令注入、权限提升、数据外泄等攻击。本文全面解析管道符的基础原理、实战应用与防御策略,涵盖Windows与Linux系统差异、攻击技术示例及检测手段,帮助安全人员掌握其利用方式与防护措施,提升系统安全性。
220 6
|
7月前
|
存储 人工智能 测试技术
HarmonyOS Next~HarmonyOS应用测试全流程解析:从一级类目上架到二级类目专项测试
本文深入解析HarmonyOS应用测试全流程,涵盖从一级类目通用测试到二级类目专项测试的技术方案。针对兼容性、性能、安全测试及分布式能力验证等关键环节,提供详细实践指导与代码示例。同时,结合典型案例分析常见问题及优化策略,帮助开发者满足华为严苛的质量标准,顺利上架应用。文章强调测试在开发中的核心地位,助力打造高品质HarmonyOS应用。
413 2
|
3月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
534 11
|
4月前
|
机器学习/深度学习 存储 分布式计算
Java 大视界 --Java 大数据机器学习模型在金融风险压力测试中的应用与验证(211)
本文探讨了Java大数据与机器学习模型在金融风险压力测试中的创新应用。通过多源数据采集、模型构建与优化,结合随机森林、LSTM等算法,实现信用风险动态评估、市场极端场景模拟与操作风险预警。案例分析展示了花旗银行与蚂蚁集团的智能风控实践,验证了技术在提升风险识别效率与降低金融风险损失方面的显著成效。
|
4月前
|
人工智能 IDE 测试技术
Browser-Use在UI自动化测试中的应用
Browser-Use是一款浏览器自动化工具,具备视觉与HTML解析、多标签管理、操作记录与复现、自定义操作、自我纠正及并行执行等功能,助力AI智能体高效完成网页任务。
388 0
|
7月前
|
安全 测试技术 Linux
Flawnter 5.9.1 (macOS, Linux, Windows) - 应用程序安全测试软件
Flawnter 5.9.1 (macOS, Linux, Windows) - 应用程序安全测试软件
265 2
Flawnter 5.9.1 (macOS, Linux, Windows) - 应用程序安全测试软件
|
Java 测试技术 数据安全/隐私保护
软件测试中的自动化策略与工具应用
在软件开发的快速迭代中,自动化测试以其高效、稳定的特点成为了质量保证的重要手段。本文将深入探讨自动化测试的核心概念、常见工具的应用,以及如何设计有效的自动化测试策略,旨在为读者提供一套完整的自动化测试解决方案,帮助团队提升测试效率和软件质量。
|
7月前
|
测试技术 数据库 Python
解释测试中setup和teardown函数的应用。
总结起来,`setup`和 `teardown`函数就像扔宴会的主人,他们保障了宴会的流畅进行。他们是准备环境和清理现场的重要工作人员,他们的工作直接影响着我们的测试效率和质量。我们可以把 `setup`和 `teardown`想象成隐藏在幕后,默默为我们服务的工作者,他们做着我们需要但是往往忽视的工作。所以,下次当你写测试的时候,别忘了给你的 `setup`和 `teardown`留出足够的位置,因为他们的作用可能是你成功的保证。
175 14
|
7月前
|
存储 5G 测试技术
时钟同步测试校验仪的应用介绍
时间同步测试仪是一种高精度、高可靠性的设备,用于测量和评估时间同步系统的性能。它广泛应用于电力系统(如电网调度、继电保护)、通信网络(如5G基站、光传输网络)、铁路交通(如列车运行控制、信号系统)、工业自动化(如生产线、控制系统)以及科学研究(如天文观测、粒子物理实验)等领域。其功能包括高精度时间测量、多信号接口支持、自动测量与分析、数据存储导出及性能评估输出,确保各领域设备间的时间同步精度与稳定性,保障系统高效运行。