gpt4 book ai didi

java - 单元测试由@Around 建议建议的方法

转载 作者:行者123 更新时间:2023-11-30 11:01:08 27 4
gpt4 key购买 nike

我目前正在为使用 Spring 和 AspectJ 的应用程序中的类编写 JUnit 单元测试。被测类有几个公共(public)方法,由方面类中的环绕建议方法建议。 Aspect 有几个注入(inject)的字段,当建议的方法被执行时,这些字段变为 null,即使我已经在测试应用程序上下文中成功实例化了这些 bean,并且当它们的方法被调用时,它们会抛出 nullpointerexceptions。这是代码的简化版本:

要测试的类:

public class ClassUnderTest {

@Inject
private Foo foo;

@Audit(StringValue="arg", booleanValue=true)
public Object advisedMethod() {
Object ret = new Object();
//things happen
return ret;
}

看点:

@Aspect
@Configurable
public class AuditAspect implements Versionable {

@Inject
Foo foo;

@Inject
Bar bar;

@Around("@annotation(Audit)")
public Object aroundAdvice(ProceedingJoinPoint pjp, Audit audit) {

// Things happen
privMethod(arg);
// Yet other things happen
Object ret = pjp.proceed();
// Still more things happen
return ret;
}

private Object privMethod(Object arg) {
// Things continue to happen.
// Then this throws a NullPointerException because bar is null.
bar.publicBarMethod(arg2);
// Method continues ...
}
}

审计界面:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Audit {
String value() default "";
boolean bool() default false;
}

提供应用上下文的配置文件:

import static org.mockito.Mockito.*;

@Configuration
public class ClassUnderTestTestConfig {

@Bean
Foo foo() {
return mock(Foo.class);
}

@Bean
Bar bar() {
return mock(Bar.class);
}

@Bean
ClassUnderTest classUnderTest() {
return new ClassUnderTest();
}

@Bean
@DependsOn({"foo", "bar"})
Aspect aspect() {
return new Aspect();
}
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextHierarchy({
@ContextConfiguration(classes = ClassUnderTestTestConfiguration.class),
@ContextConfiguration(classes = ClassUnderTest.class)
})
public class ClassUnderTestTest {

private static final String sessionNumber = "123456";

@Inject
Foo foo;

@Inject
Bar bar;

@Inject
ClassUnderTest classUnderTest;

@Inject
Aspect aspect;

@Test
public void test() {
// This call triggers the advice which ends up throwning
// a NullPointerException.
classUnderTest.advised();
}
}

我还尝试制作自己的 Spring 代理,然后按照 this stack overflow post 中的建议手动将方面添加到它,方法是将此代码添加到测试类:

@Before
public void setUp() {
DataPointRestWebService target = new DataPointRestWebService();
AspectJProxyFactory proxyMaker = new AspectJProxyFactory(target);
proxyMaker.addAspect(auditAspect);
dataPointRestWebService = proxyMaker.getProxy();
}

然而最终抛出:

AopConfigException: Advice must be declared inside an aspect type. Offending method 'public java.lang.Object Aspect.aroundAdvice' in class [Aspect]

我觉得这很神秘,因为我的 Aspect 类前面确实有 @Aspect 注释,并且该类在测试环境之外工作。

我是 Spring 和 AspectJ 的新手,所以我完全接受我正在做这一切的想法。我在这里提供了虚拟代码,希望能省略无用的细节,但也因为工作代码是专有的,而不是我的。如果您认为我遗漏了重要的细节,请告诉我,我会尝试添加。

在此先感谢您的帮助,如果我遗漏了任何重要信息,请告诉我。

编辑:

根据要求,我添加了完整的 NullPointerException 堆栈跟踪:

java.lang.NullPointerException
at com.unifiedcontrol.aspect.AuditAspect.getCaller(AuditAspect.java:265)
at com.unifiedcontrol.aspect.AuditAspect.ajc$inlineAccessMethod$com_unifiedcontrol_aspect_AuditAspect$com_unifiedcontrol_aspect_AuditAspect$getCaller(AuditAspect.java:1)
at com.unifiedcontrol.aspect.AuditAspect.aroundAuditAdvice(AuditAspect.java:79)
at com.unifiedcontrol.server.rest.DataPointRestWebServiceTest.dummyTest(DataPointRestWebServiceTest.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

其中 AuditAspect == Aspect 和 DataPointRestWebService == ClassUnderTest。

最佳答案

这是最终解决我们问题的方法:

我们更改了 ClassUnderTestTestConfig 类中的以下方法:

@Bean
@DependsOn({"foo", "bar"})
Aspect aspect() {
return new Aspect();
}

到:

@Bean
@DependsOn({"foo", "bar"})
Aspect aspect() {
return Aspects.aspectOf(Aspect.class);
}

为此我们添加了以下导入语句:

import org.aspectj.lang.Aspects;

原始代码成功返回了一个新的 Aspect 对象,但是当调用 ClassUnderTest.advisedMethod() 时,jointpoint 被委托(delegate)给另一个未注入(inject)非空 foo 和 bar 成员的 Aspect 对象。关于 Aspects.aspectOf() 方法如何工作的一些信息确保由 TestConfig 创建的 Aspect 对象是为调用 advisedMethod() 提供建议的对象。

目前我不知道为什么这样可以解决问题。工作中的其他人找到了解决方案。我计划调查它并使用更多信息编辑这篇文章,但与此同时欢迎所有贡献。

关于java - 单元测试由@Around 建议建议的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31329009/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com