Spring AOP-@Pointcut:@Test方法的@Before建议不起作用

Man*_*dan 2 junit aop aspectj spring-aop

我正在与:

  • Spring Framework 4.3.2
  • AspectJ 1.8.9
  • JUnit的
  • 摇篮

该项目基于多模块。

src/main/javamain)中,我有一些@Aspect课程,它们的工作原理如何。我可以通过运行时和测试来确认

现在我需要通过日志记录显示@Test执行的方法名称的JUnit

因此,在src/test/javatest)中,我具有以下内容:

class TestPointcut {

    @Pointcut("execution(@org.junit.Test * *())")                         
    public void testPointcut(){}

}

@Aspect
@Component
public class TestAspect {

    private static final Logger logger = LoggerFactory.getLogger(TestAspect.class.getSimpleName());

    @Before(value="TestPointcut.testPointcut()")
    public void beforeAdviceTest(JoinPoint joinPoint){
        logger.info("beforeAdviceTest - Test: {} - @Test: {}", joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName() );
    }

}
Run Code Online (Sandbox Code Playgroud)

观察第二类@Aspect@Component因此Spring可以识别它。

注意:我可以确认如果我写错了@Pointcut语法或表达式,我会得到错误。

问题是当我执行我的@Test方法时,对于TestAspect该类的@Before建议永远不会起作用。

我在Google上进行了一项研究,发现该@Pointcut("execution(@org.junit.Test * *())")模式是正确的。即使我使用更明确的诸如:@Pointcut(value="execution(public void com.manuel.jordan.controller.persona.*Test.*Test())"),它也不起作用。

考虑我有以下几点 Gradle

project(':web-27-rest') {
    description 'Web - Rest'
    dependencies {
       compile project(':web-27-service-api')

       testRuntime project(':web-27-aop')
       testRuntime project(':web-27-aop').sourceSets.test.output
Run Code Online (Sandbox Code Playgroud)

遗漏或错了什么?

Alpha

一种测试类是:

  • 服务器端使用@Parametersand @ClassRule+@Rule

因此:

@RunWith(Parameterized.class)
@ContextConfiguration(classes={RootApplicationContext.class})
@Transactional
public class PersonaServiceImplTest {

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE= new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Autowired
    private PersonaService personaServiceImpl;

    ...

    @Parameters
    public static Collection<Persona[]> data() {
     .....
        });
    }

    ...

    @Test
    @Sql(scripts={"classpath:....-script.sql"})
    public void saveOneTest(){
    ....
    }
Run Code Online (Sandbox Code Playgroud)

其他是:

  • Web端使用(@WebAppConfiguration),并且可以:
    • @Parameters@ClassRule+@Rule
    • 没有@Parameters@ClassRule+@Rule

因此(在第二种方法下面):

@Transactional
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
public class PersonaDeleteOneControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    private ResultActions resultActions;

    ...

    @BeforeClass
    public static void setUp_(){
      ...
    }

    @Before
    public void setUp(){
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void deleteOneHtmlGetTest() throws Exception {
Run Code Online (Sandbox Code Playgroud)

Sam*_*nen 5

JUnit实例化您的测试类。因此,Spring不参与其中,因此无法将AOP建议应用于测试实例。

正如Sergey Bespalov所提到的,将AspectJ建议应用于您的测试实例的唯一方法是使用编译时或加载时编织。请注意,这不会在Spring中配置。Spring可以用于为Spring托管的bean配置AOP,但是测试实例由测试框架(即您的方案中的JUnit 4)管理。

但是,对于使用Spring TestContext Framework的测试,我不建议使用AspectJ。相反,最好的解决方案是实现一个TestExecutionListener执行日志记录的自定义。然后,您可以TestExecutionListener通过进行显式注册,@TestExecutionListeners或者在整个套件中自动进行注册。对于后者,请参见Spring参考手册“测试”一章中有关自动发现的讨论。

问候,

Sam(Spring TestContext Framework的作者

  • 始终是跑步者实例化您的测试课程。因此,如果您使用的是“ Parameterized”运行器,则是该运行器实例化您的测试类(不是Spring)。如果您使用的是SpringJUnit4ClassRunner,您可以_think_ Spring实例化您的测试类。但是,`SpringJUnit4ClassRunner`实际上是JUnit的`BlockJUnit4ClassRunner`的扩展,而`BlockJUnit4ClassRunner`物理上实例化了测试实例(同样不是Spring)。 (3认同)