Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单元测试由@Around advice建议的方法_Java_Spring_Unit Testing_Junit - Fatal编程技术网

Java 单元测试由@Around advice建议的方法

Java 单元测试由@Around advice建议的方法,java,spring,unit-testing,junit,Java,Spring,Unit Testing,Junit,我目前正在为使用Spring和AspectJ的应用程序中的一个类编写JUnit单元测试。被测试的类有两个公共方法,它们由方面类中的around advice方法提供建议。尽管我已经在测试应用程序上下文中成功地实例化了这些bean,并且当调用它们的方法时,它们抛出NullPointerException,但方面有两个注入的字段,在执行建议的方法时,这些字段将显示为null。下面是代码的简化版本: 要测试的类别: public class ClassUnderTest { @Inject

我目前正在为使用Spring和AspectJ的应用程序中的一个类编写JUnit单元测试。被测试的类有两个公共方法,它们由方面类中的around advice方法提供建议。尽管我已经在测试应用程序上下文中成功地实例化了这些bean,并且当调用它们的方法时,它们抛出NullPointerException,但方面有两个注入的字段,在执行建议的方法时,这些字段将显示为null。下面是代码的简化版本:

要测试的类别:

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();
    }
}
@Before
public void setUp() {
    DataPointRestWebService target = new DataPointRestWebService();
    AspectJProxyFactory proxyMaker = new AspectJProxyFactory(target);
    proxyMaker.addAspect(auditAspect);
    dataPointRestWebService = proxyMaker.getProxy();
}
我还尝试创建自己的Spring代理,然后按照中的建议手动向其添加方面,方法是将以下代码添加到测试类:

@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();
    }
}
@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。

以下是最终解决问题的方法:

我们在ClassUnderTestConfig类中更改了以下方法:

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

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

import org.aspectj.lang.Aspects;
原始代码成功地返回了一个新的方面对象,但是当调用ClassUnderTest.advisedMethod()时,jointpoint被委托给了一个不同的方面对象,该方面对象没有注入非null的foo和bar成员。Aspects.aspectOf()方法的工作原理确保了TestConfig创建的Aspect对象是为advisedMethod()调用提供建议的对象


目前我不知道这为什么解决了这个问题。工作中的其他人找到了解决方案。我计划深入研究并编辑这篇文章,提供更多信息,但同时欢迎所有投稿。

你的例子对我来说很好(没有之前的
@方法)。你能发布完整的NPE堆栈跟踪吗?刚刚添加了它。感谢您抽出时间。您似乎在
AuditAspect
中遗漏了一些重要内容。你能提供一个完整的和可复制的例子吗?我在修改我的方面时遇到了这个问题。以前,我需要像这样手动将方面编织到类中:
AspectJProxyFactory factory=newaspectjproxyfactory(service)
factory.addAspect(新方面())`service=factory.getProxy();