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,如需转载请自行联系原作者

相关文章
|
11天前
|
数据采集 人工智能 安全
软件测试中的人工智能应用与挑战
在这篇文章中,我们将深入探讨人工智能(AI)在软件测试中的应用及其所面临的挑战。通过分析当前的技术趋势和具体案例,揭示AI如何提高测试效率和准确性,并指出在实施过程中遇到的主要问题及可能的解决途径。
25 1
|
22天前
|
人工智能 数据可视化 API
10 分钟构建 AI 客服并应用到网站、钉钉或微信中测试评
10 分钟构建 AI 客服并应用到网站、钉钉或微信中测试评
61 2
|
7天前
|
测试技术
探索软件测试的奥秘:从基础理论到实践应用
【9月更文挑战第28天】在数字化时代,软件已成为我们生活中不可或缺的一部分。然而,随着软件复杂性的增加,确保其质量和可靠性变得日益重要。本文将带你深入了解软件测试的核心概念、方法论以及如何在实际工作中运用这些知识来提升软件质量。无论你是软件测试新手还是希望深化理解,这篇文章都将为你提供宝贵的洞见和实用技巧。
|
19天前
|
敏捷开发 IDE 测试技术
自动化测试框架的选择与应用
【9月更文挑战第16天】在软件开发周期中,测试环节扮演着至关重要的角色。随着敏捷开发和持续集成的流行,自动化测试成为提升软件质量和效率的关键手段。本文将探讨如何根据项目需求选择合适的自动化测试框架,并通过实际案例分析展示其在软件开发过程中的应用。我们将从单元测试、集成测试到端到端测试等多个层面,讨论自动化测试的最佳实践和常见问题解决策略。
|
9天前
|
敏捷开发 Java 测试技术
自动化测试框架的选择与应用
【9月更文挑战第26天】在软件开发的海洋里,自动化测试是那一盏指路明灯。它不仅加快了开发周期,还提升了软件质量。本文将带你探索自动化测试框架的世界,了解它们的核心特性、适用场景及如何根据项目需求做出明智选择。让我们一起启航,找到那把打开高效、稳定软件生产大门的钥匙。
|
7天前
|
数据采集 人工智能 自然语言处理
软件测试中的人工智能应用与挑战
本文探讨了人工智能在软件测试中的应用及其所面临的挑战。通过分析AI技术如何优化测试流程、提高测试效率以及目前存在的局限性,文章提供了对软件测试未来发展趋势的深入思考。
|
9天前
|
机器学习/深度学习 人工智能 监控
软件测试中的人工智能应用与挑战
随着科技的迅猛发展,人工智能(AI)在软件测试中的应用越来越广泛。本文将探讨AI在软件测试中的具体应用场景、带来的优势以及所面临的挑战,旨在为软件开发和测试人员提供有价值的参考。
|
11天前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
|
10天前
|
测试技术 持续交付 UED
软件测试的艺术与科学:平衡创新与质量的探索在软件开发的波澜壮阔中,软件测试如同灯塔,指引着产品质量的方向。本文旨在深入探讨软件测试的核心价值,通过分析其在现代软件工程中的应用,揭示其背后的艺术性与科学性,并探讨如何在追求技术创新的同时确保产品的高质量标准。
软件测试不仅仅是技术活动,它融合了创造力和方法论,是软件开发过程中不可或缺的一环。本文首先概述了软件测试的重要性及其在项目生命周期中的角色,随后详细讨论了测试用例设计的创新方法、自动化测试的策略与挑战,以及如何通过持续集成/持续部署(CI/CD)流程优化产品质量。最后,文章强调了团队间沟通在确保测试有效性中的关键作用,并通过案例分析展示了这些原则在实践中的应用。
29 1
|
19天前
|
数据采集 人工智能 自然语言处理
探索软件测试中的人工智能应用
在当今快速发展的技术世界中,软件测试作为确保软件质量的关键环节,正经历着前所未有的变革。随着人工智能技术的不断成熟和应用,其在软件测试领域的潜力逐渐显现,为提升测试效率、准确性和自动化水平提供了新的可能性。本文将深入探讨人工智能在软件测试中的应用现状、面临的挑战以及未来的发展趋势,旨在为读者提供一个关于AI如何改变软件测试行业的全面视角。
下一篇
无影云桌面