Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@TestBean and @MockitoBean tests fail in AOT mode #32925

Closed
sbrannen opened this issue May 30, 2024 · 2 comments
Closed

@TestBean and @MockitoBean tests fail in AOT mode #32925

sbrannen opened this issue May 30, 2024 · 2 comments
Labels
in: test Issues in the test module status: duplicate A duplicate of another issue type: bug A general bug

Comments

@sbrannen
Copy link
Member

sbrannen commented May 30, 2024

Overview

When running various bean override tests in AOT mode (via AotIntegrationTests), AOT processing fails with a stack trace similar to the following.

org.springframework.test.context.aot.TestContextAotException: Failed to generate AOT artifacts for test classes [org.springframework.test.context.bean.override.convention.TestBeanByTypeIntegrationTests]
	at org.springframework.test.context.aot.TestContextAotGenerator.lambda$10(TestContextAotGenerator.java:281)
	at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
	at org.springframework.util.MultiValueMapAdapter.forEach(MultiValueMapAdapter.java:179)
	at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:244)
	at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:205)
	at org.springframework.test.context.aot.AotIntegrationTests.runEndToEndTests(AotIntegrationTests.java:166)
	at org.springframework.test.context.aot.AotIntegrationTests.endToEndTestsForSelectedTestClasses(AotIntegrationTests.java:159)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.core.test.tools.CompileWithForkedClassLoaderExtension.intercept(CompileWithForkedClassLoaderExtension.java:97)
	at org.springframework.core.test.tools.CompileWithForkedClassLoaderExtension.interceptTestMethod(CompileWithForkedClassLoaderExtension.java:83)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.springframework.test.context.aot.TestContextAotException: Failed to process test class [org.springframework.test.context.bean.override.convention.TestBeanByTypeIntegrationTests] for AOT
	at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:317)
	at org.springframework.test.context.aot.TestContextAotGenerator.lambda$10(TestContextAotGenerator.java:273)
	... 11 more
Caused by: java.lang.IllegalStateException: No constructor or factory method candidate found for Root bean: class [null]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null and argument types []
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorOrFactoryMethod(ConstructorResolver.java:996)
	at org.springframework.beans.factory.support.RegisteredBean.resolveConstructorOrFactoryMethod(RegisteredBean.java:218)
	at org.springframework.beans.factory.support.RegisteredBean.resolveInstantiationDescriptor(RegisteredBean.java:228)
	at org.springframework.util.function.SingletonSupplier.get(SingletonSupplier.java:106)
	at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.getTarget(DefaultBeanRegistrationCodeFragments.java:86)
	at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:85)
	at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$3(BeanRegistrationsAotContribution.java:89)
	at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
	at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterBeanDefinitionsMethod(BeanRegistrationsAotContribution.java:87)
	at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$1(BeanRegistrationsAotContribution.java:72)
	at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54)
	at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112)
	at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89)
	at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:71)
	at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78)
	at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$0(ApplicationContextAotGenerator.java:58)
	at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
	at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
	at org.springframework.test.context.aot.TestContextAotGenerator.processAheadOfTime(TestContextAotGenerator.java:314)
	... 12 more

The key part is this:

No constructor or factory method candidate found for Root bean: class [null]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null and argument types []

... which seems like a relatively empty BeanDefinition.

Failing Test Classes

  • TestBeanByTypeIntegrationTests
  • TestBeanInheritanceIntegrationTests$ConcreteTestBeanIntegrationTests
  • MockitoBeanByTypeIntegrationTests
  • MockitoBeanIntegrationTests

Related Issues

@sbrannen sbrannen added in: test Issues in the test module type: bug A general bug labels May 30, 2024
@sbrannen sbrannen added this to the 6.2.0-M4 milestone May 30, 2024
@sbrannen sbrannen changed the title @TestBean "by type" tests fail in AOT mode @TestBean "by type" tests and @MockitoBean tests fail in AOT mode May 30, 2024
@snicoll snicoll modified the milestones: 6.2.0-M4, 6.2.x May 31, 2024
sbrannen added a commit that referenced this issue May 31, 2024
As a follow up to the previous commit (31f8e12), this commit
polishes bean override tests and revises them with a focus on AOT
testing support and simplified maintenance.

- Introduce EngineTestKitUtils to simplify working with JUnit's
  EngineTestKit.

- Use idiomatic EngineTestKit APIs to simplify assertions on
  EngineTestKit results.

- Introduce BeanOverrideTestSuite to simplify running all bean override
  tests within the IDE.

- Separate failure and success scenario tests, so that failure tests do
  not launch the JUnit Platform to run tests using the Spring
  TestContext Framework (TCF) within a test class that itself uses the
  TCF.

- Make AbstractTestBeanIntegrationTestCase actually abstract.

- Rename test case classes to give them meaningful names and simplify
  understanding of what's being tested.

- Ensure tests for @⁠MockitoSpyBean functionality use @⁠MockitoSpyBean
  instead of @⁠MockitoBean.

- Declare @⁠Configuration classes local to @⁠SpringJUnitConfig test
  classes whenever possible.

See gh-29122
See gh-32925
@sbrannen sbrannen changed the title @TestBean "by type" tests and @MockitoBean tests fail in AOT mode @TestBean and @MockitoBean tests fail in AOT mode May 31, 2024
@snicoll
Copy link
Member

snicoll commented Jun 1, 2024

Quoting #32933:

Although @MockitoBean and @MockitoSpyBean will not work out-of-the-box within a GraalVM native image due to their dependency on Mockito, the general Bean Override support for tests should ideally work within a native image.

That is partially accurate. The mockito support in Spring Boot never worked in AOT mode on the JVM. It current fails as follows:

Caused by: org.springframework.aot.generate.UnsupportedTypeValueCodeGenerationException: Code generation does not support org.springframework.boot.test.mock.mockito.MockDefinition
	at org.springframework.aot.generate.ValueCodeGenerator.generateCode(ValueCodeGenerator.java:113)
	... 42 more

That is because the TCF requires the key for a context to be computed at a certain time and makes it very AOT unfriendly as a result. I think this issue needs to be requalified as we need to fix that.

Next up, the support works by registering a singleton with a "dummy" bean definition and that's why this is failing.

@snicoll
Copy link
Member

snicoll commented Jun 6, 2024

This issue is no longer relevant as it's obvious that bean overriding does not work with AOT. And we already have an issue to investigate how to fix that, see #32933

@snicoll snicoll closed this as not planned Won't fix, can't repro, duplicate, stale Jun 6, 2024
@snicoll snicoll removed this from the 6.2.x milestone Jun 6, 2024
@snicoll snicoll added the status: duplicate A duplicate of another issue label Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module status: duplicate A duplicate of another issue type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants