Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.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 在Spring测试中未调用方面_Java_Spring_Spring Aop_Spring Test_Spring Aspects - Fatal编程技术网

Java 在Spring测试中未调用方面

Java 在Spring测试中未调用方面,java,spring,spring-aop,spring-test,spring-aspects,Java,Spring,Spring Aop,Spring Test,Spring Aspects,我使用的是Spring4.16,我有我的ValidationSpect,它验证方法参数,并在出现错误时抛出ValidationException。当我运行服务器并发送请求时,会调用此函数,但当来自测试时不会调用此函数: package com.example.movies.domain.aspect; ... @Aspect public class ValidationAspect { private final Validator validator; public Va

我使用的是Spring4.16,我有我的ValidationSpect,它验证方法参数,并在出现错误时抛出ValidationException。当我运行服务器并发送请求时,会调用此函数,但当来自测试时不会调用此函数:

package com.example.movies.domain.aspect;
...
@Aspect
public class ValidationAspect {

    private final Validator validator;

    public ValidationAspect(final Validator validator) {
        this.validator = validator;
    }

    @Pointcut("execution(* com.example.movies.domain.feature..*.*(..))")
    private void selectAllFeatureMethods() {
    }

    @Pointcut("bean(*Service)")
    private void selectAllServiceBeanMethods() {
    }

    @Before("selectAllFeatureMethods() && selectAllServiceBeanMethods()")
    public synchronized void validate(JoinPoint joinPoint) {
         // Validates method arguments which are annotated with @Valid
    }
}
我在其中创建方面bean的配置文件

package com.example.movies.domain.config;
...
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AspectsConfiguration {

    @Bean
    @Description("Hibernate validator. Used to validate request's input")
    public Validator validator() {
        ValidatorFactory validationFactory = Validation.buildDefaultValidatorFactory();
        return validationFactory.getValidator();
    }

    @Bean
    @Description("Method validation aspect")
    public ValidationAspect validationAspect() {
        return new ValidationAspect(this.validator());
    }
}
这就是测试,它应该在进入addSoftware方法之前抛出ValidationException,因为它是一个无效的softwareObject

@ContextConfiguration
@ComponentScan(basePackages = {"com.example.movies.domain"})
public class SoftwareServiceTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(SoftwareServiceTests.class.getName());

    private SoftwareService softwareService;
    @Mock
    private SoftwareDAO dao;
    @Mock
    private MapperFacade mapper;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        this.softwareService = new SoftwareServiceImpl(this.dao);
        ((SoftwareServiceImpl) this.softwareService).setMapper(this.mapper);

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SoftwareServiceTests.class);
        ctx.getBeanFactory().registerSingleton("mockedSoftwareService", this.softwareService);
        this.softwareService = (SoftwareService) ctx.getBean("mockedSoftwareService");

    }

    @Test(expected = ValidationException.class)
    public void testAddInvalidSoftware() throws ValidationException {
        LOGGER.info("Testing add invalid software");
        SoftwareObject softwareObject = new SoftwareObject();
        softwareObject.setName(null);
        softwareObject.setType(null);

        this.softwareService.addSoftware(softwareObject); // Is getting inside the method without beeing validated so doesn't throws ValidationException and test fails
    }
}
如果我运行该服务,并从post请求中添加该无效用户,则会按原样引发ValidationException。但由于某些原因,它从未从测试层执行ValidationSpect方法

还有我的服务

package com.example.movies.domain.feature.software.service;
...
@Service("softwareService")
public class SoftwareServiceImpl
    implements SoftwareService {

    @Override
    public SoftwareObject addSoftware(@Valid SoftwareObject software) {
         // If gets into this method then software has to be valid (has been validated by ValidationAspect since is annotated with @Valid)
         // ...
    }
}
我不明白为什么不调用aspect,因为MockedSoftwareServicebean位于FeaturePackage中,并且bean名称以“Service”结尾,所以它满足这两个条件。你知道会发生什么吗?提前谢谢


编辑
不确定您想做什么,但是您的
@ContextConfiguration
没有用,因为您没有使用Spring测试来运行测试(这需要
@RunWith
或Spring测试中的一个超类)

接下来,您将添加一个已经完全模拟和配置的单例(这是上下文假定的)。我强烈建议使用Spring,而不是围绕它工作

首先在您的测试类中创建一个用于测试的配置,这个配置应该扫描并注册模拟bean。第二,使用Spring测试运行您的测试

@ContextConfiguration
public class SoftwareServiceTests extends AbstractJUnit4SpringContextTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(SoftwareServiceTests.class.getName());

    @Autowired
    private SoftwareService softwareService;

    @Test(expected = ValidationException.class)
    public void testAddInvalidSoftware() throws ValidationException {
        LOGGER.info("Testing add invalid software");
        SoftwareObject softwareObject = new SoftwareObject();
        softwareObject.setName(null);
        softwareObject.setType(null);

        this.softwareService.addSoftware(softwareObject);
    }

    @Configuration
    @Import(AspectsConfiguration.class)
    public static class TestConfiguration {

        @Bean
        public SoftwareDAO softwareDao() {
            return Mockito.mock(SoftwareDAO.class);
        }

        @Bean
        public MapperFacade domainMapper() {
            return Mockito.mock(MapperFacade.class)
        }

        @Bean
        public SoftwareService softwareService() {
            SoftwareServiceImpl service = new SoftwareServiceImpl(softwareDao())
            return service;
        }

    }
}

了解SpringAOP是如何工作的很好。如果Spring管理的bean符合任何方面(每个方面一个代理)的条件,那么它将被包装在一个代理(或几个代理)中

通常,Spring使用接口创建代理,尽管它可以使用库(如cglib)处理常规类。对于您的服务,这意味着Spring创建的实现实例被包装在一个代理中,该代理处理方法验证的方面调用

现在,您的测试手动创建SoftwareServiceImpl实例,因此它不是Spring管理的bean,因此Spring没有机会将其封装在代理中,以便能够使用您创建的特性


您应该使用Spring来管理bean,以使方面工作。

确实有两件重要的事情需要实现:

1) 对象树的根必须由应用程序上下文中注册的扫描对象解析。如果您使用new(),就不可能解析AOP注释

2) 注释和AOP方面类需要注册

ad 1)@Autowire您的根对象将完成此任务

ad 2)确保@Component使用了正确的过滤器: @Component()或@Component(“您的完整命名空间包筛选器”)

检查:

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) 
    {
        return args -> 
        {
            log.debug("Let's inspect the beans provided by Spring Boot:");

            List<String> beanNames = Arrays.asList(ctx.getBeanDefinitionNames());
            Assert.isTrue( beanNames.contains("yourAspectClassName"));

        };
    }
@Bean
公共命令行运行程序命令行运行程序(ApplicationContext ctx)
{
返回参数->
{
debug(“让我们检查SpringBoot提供的bean:”);
List beanNames=Arrays.asList(ctx.getBeanDefinitionNames());
isTrue(beanNames.contains(“yourAspectClassName”);
};
}

方面类是否定义在测试配置xml中?请提供您的测试配置xml。(由@Rodrigo Gomes请求)尝试添加
@RunWith(SpringJUnit4ClassRunner.class)
,因为Junit尚未附加到spring上下文:)@Barett我没有任何xml配置。它全部由java注释配置。方面配置正是我在那里提出的。谢谢你的回答@Bond JavaBond我将该RunWith行放入,得到“非法状态异常:GenericXmlContextLoader和AnnotationConfigContextLoader都无法检测默认值,并且没有为上下文配置[ContextConfigurationAttributes]声明ApplicationContextInitializers…”如果在测试上下文中定义bean并将其注入测试用例,会发生什么?我认为问题是一个非托管bean。谢谢您的回复。我没有得到这样的bean定义异常:没有[ma.glasnost.orika.MapperFacade]类型的合格bean。你知道会发生什么吗?那么你还没有包括正确的bean或它们的模拟。你有正确的映射类吗?你没有(出于某种原因)在某个地方进行组件扫描吗?我还想知道为什么你有自己的一面?Spring已经有了
MethodValidationInterceptor
(尽管这只适用于hibernate验证器)。您的理解是错误的
MethodValidationInterceptor
只适用于控制器之外的所有东西。控制器有本机支持,其他组件没有。请将
mapper
重命名为
domainMapper
。你还有
@Autowired
为什么还要手动注射?我已经解决了这个问题!问题与你刚才说的有关。谢谢在花了24小时之后,这真是一个非常好的建议:)
    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) 
    {
        return args -> 
        {
            log.debug("Let's inspect the beans provided by Spring Boot:");

            List<String> beanNames = Arrays.asList(ctx.getBeanDefinitionNames());
            Assert.isTrue( beanNames.contains("yourAspectClassName"));

        };
    }