For Spring Framework 6.0.4 --- regarding testing with JUnit Jupiter -- the following works fine.

@AfterEach
void afterEach(@Autowired CienciaService cienciaService) {
      System.out.println("afterEach ...");
      ...
}

The point is that an @AfterEach method accepts injection through parameters at runtime. Same as @BeforeAll, I am assuming @BeforeEach works as well.

Now the following:

@AfterTransaction
void afterTransaction(@Autowired CienciaService cienciaService) {
      System.out.println("afterTransaction ...");
      ...
}

That compiles, but at runtime we get:

Jun 23, 2023 7:04:05 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener runAfterTransactionMethods
SEVERE: Exception encountered while executing @AfterTransaction method [void com.manuel.jordan.service.process.ProcessServiceTests.afterTransaction(com.manuel.jordan.service.CienciaService,com.manuel.jordan.service.CientificoService)] for test context [DefaultTestContext@30cdae70 testClass = com.manuel.jordan.service.process.ProcessServiceTests, testInstance = com.manuel.jordan.service.process.ProcessServiceTests@1654a892, testMethod = processServiceCreateV2Test(CienciaService, CientificoService), testException = null, mergedContextConfiguration = [MergedContextConfiguration@3163987e testClass = com.manuel.jordan.service.process.ProcessServiceTests, locations = [], classes = [com.manuel.jordan.config.AppConfig], contextInitializerClasses = [], activeProfiles = ["pre-prod", "cache", "exception-unchecked-try-catch-non"], propertySourceLocations = [], propertySourceProperties = [], contextCustomizers = [], contextLoader = org.springframework.test.context.support.DelegatingSmartContextLoader, parent = null], attributes = {"org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents" -> false}]
java.lang.IllegalArgumentException: wrong number of arguments
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)

Questions

What is the reason for this?

I am assuming that @BeforeTransaction has the same situation. Currently as a workaround I use:

@Autowired
ApplicationContext applicationContext;
...

@AfterTransaction
void afterTransaction() {
      CienciaService cienciaService = applicationContext.getBean(CienciaService.class);
      System.out.println("afterTransaction ...");
      ...  
}

Note the injected @Service classes are @Transactional

Comment From: sbrannen

What is the reason for this?

The reason is that JUnit Jupiter invokes JUnit lifecycle methods such as @BeforeAll, @AfterEach, etc.

Whereas, Spring invokes @BeforeTransaction and @AfterTransaction methods, and Spring has done that agnostic of the underlying testing framework since long before JUnit Jupiter existed.

Fortunately, it should be possible for Spring to delegate to JUnit Jupiter to invoke @BeforeTransaction and @AfterTransaction methods with parameter injection by using the ExecutableInvoker API that was introduced in JUnit Jupiter 5.9.

Of course, that means this functionality would only be available to JUnit Jupiter tests (and not to JUnit 4 or TestNG tests). So we will have to introduce a Spring-specific abstraction over the ExecutableInvoker API for Spring TestExecutionListener implementations.

I'll see what's possible...

Comment From: manueljordan

Thanks for the feedback, if is not possible, the current reference documentation should be updated to indicate this "constraint".

Comment From: sbrannen

FWIW, I actually documented this in JUnit 5's issue tracker quite a long time ago. 😉

https://github.com/junit-team/junit5/issues/2191#issuecomment-857625023

Comment From: sbrannen

  • Depends on #31199

Comment From: manueljordan

FWIW, I actually documented this in JUnit 5's issue tracker quite a long time ago. 😉 https://github.com/junit-team/junit5/issues/2191#issuecomment-857625023

Thanks for the link, but I meant about Spring Framework Reference documentation. Yes, it is tricky: in what documentation should be located this case. For JUnit or SF?, because Autowire and Transactions is involved I expected to see this in the SF Reference documentation. I hope you see my point

Comment From: sbrannen

This has been addressed in ed83461021374bb7b3df654b8f37c1b56d3288dd.

Feel free to try it out in 6.1 M5 snapshot builds.