我碰到了一篇有趣的文章:AOP Aspects as mocks in JUnit
由于我需要模拟多个最终和私有静态变量,因此我计划使用AOP代替反射或PowerMockito,因为它们会导致SpringJUnit4ClassRunner
出现问题。
有什么方法可以将@Aspect
用于测试类而无需使用注释@EnableAspectJAutoProxy
? (我只想在一个测试用例中使用面向类X的方面。)
这是我想做的事的一个例子。
问题已经回答(正在讨论可以做什么)
//External class
public final class ABC(){
public void method1() throws Exception {}
}
@Service
public void DestClass() {
private static final ABC abc = new ABC();
public Object m() {
// code (...)
try {
abc.method1();
}
catch(Exception e) {
// do something (...)
return null;
}
// more code (...)
}
}
答案 0 :(得分:0)
Spring框架允许以编程方式创建建议目标对象的代理,而无需通过@EnableAspectJAutoProxy
或<aop:aspectj-autoproxy>
进行配置
可以在文档部分Programmatic Creation of @AspectJ Proxies中找到详细信息,其实现非常简单。
文档中的示例代码。
// create a factory that can generate a proxy for the given target object
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an @AspectJ aspect
// you can call this as many times as you need with different aspects
factory.addAspect(SecurityManager.class);
// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect
factory.addAspect(usageTracker);
// now get the proxy object...
MyInterfaceType proxy = factory.getProxy();
请注意,使用Spring AOP时,只能建议方法执行。摘自documentation
Spring AOP当前仅支持方法执行连接点 (建议在Spring bean上执行方法)。领域 尽管支持字段,但拦截尚未实现 可以在不破坏核心Spring AOP API的情况下添加拦截功能。 如果您需要建议现场访问和更新连接点,请考虑 语言,例如AspectJ。
与该问题共享的文档是关于Aspectj的,并且在没有提供示例代码的情况下,很难推断出是否可以通过Spring AOP实现需求。该文档也提到了这一点。
与AspectJ集成的一个示例是Spring框架, 现在可以在其自己的AOP中使用AspectJ切入点语言 实施。 Spring的实施并非专门针对 作为测试解决方案。
希望这会有所帮助。
---更新:不使用AOP的测试用例---
考虑外部类
public class ABCImpl implements ABC{
@Override
public void method1(String example) {
System.out.println("ABC method 1 called :"+example);
}
}
还有DestClass
@Service
public class DestClass {
private static final ABC service = new ABCImpl();
protected ABC abc() throws Exception{
System.out.println("DestClass.abc() called");
return service;
}
public Object m() {
Object obj = new Object();
try {
abc().method1("test");
} catch (Exception e) {
System.out.println("Exception : "+ e.getMessage());
return null;
}
return obj;
}
}
下面的测试类将DestClass
bean与重写逻辑自动关联以引发异常。可以修改此代码以适应您的要求。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { DestClassSpringTest.TestConfiguration.class })
public class DestClassSpringTest {
@Configuration
static class TestConfiguration {
@Bean
public DestClass destClass() {
return new DestClass() {
protected ABC abc() throws Exception {
// super.abc(); // not required . added to demo the parent method call
throw new Exception("Custom exception thrown");
}
};
}
}
@Autowired
DestClass cut;
@Test
public void test() {
Object obj = cut.m();
assertNull(obj);
}
}
以下将是输出日志
DestClass.abc() called // this will not happen if the parent method call is commented in DestClassSpringTest.TestConfiguration
Exception : Custom exception thrown
答案 1 :(得分:0)
您所指的文章使用的是完整的AspectJ,而不是Spring AOP。因此,您不需要任何@EnableAspectJAutoProxy
,只需
-javaagent:/path/to/aspectjweaver.jar
运行测试时,在命令行上之一
或编译测试时激活了AspectJ编译器(如果使用Maven,则可以通过AspectJ Maven插件轻松完成)
这两种方法都完全独立于Spring,在任何项目中都可以使用,即使在使用Spring时也可以在针对第三方代码的执行中使用,因为与Spring AOP不同,不需要动态代理。因此,无需将目标代码放入Spring bean或在应用程序类中为其创建包装方法。使用编译时编织时,您甚至可以避免使用call()
而不是execution()
切入点编织到第三方库中。 Spring AOP只知道execution()
,AspectJ更强大。
顺便说一句:不幸的是,您的问题和对找到的解决方案的评论都有些模糊,我不完全理解您的要求。例如。您谈到了模拟最终静态变量和私有静态变量,这也可以通过使用set()
和/或get()
切入点以其他方式在AspectJ中实现。但是实际上,您似乎不需要模拟字段内容,只需将方法调用的结果存入分配给这些字段的对象上即可。