Skip to content

WithMockUser does not work when running tests in a native image #12189

Closed
@wilkinsona

Description

@wilkinsona

Describe the bug
If @WithMockUser is used in a test that is run in a native image, it will fail as WithMockUserSecurityContextFactory cannot be instantiated due to missing reflection hints:

2022-11-09T22:23:27.680Z  WARN 836 --- [           main] o.s.test.context.TestContextManager      : Caught exception while invoking 'beforeTestMethod' callback on TestExecutionListener [org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener@2d8b79e9] for test method [public void com.example.security.thymeleaf.SecurityThymeleafApplicationTests.accessSecuredResourceAuthenticatedThenOk() throws java.lang.Exception] and test instance [com.example.security.thymeleaf.SecurityThymeleafApplicationTests@5a7a2dec]	
java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.test.context.support.WithMockUserSecurityContextFactory': Failed to instantiate [org.springframework.security.test.context.support.WithMockUserSecurityContextFactory]: No default constructor found	
	at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createFactory(WithSecurityContextTestExecutionListener.java:176) ~[security-thymeleaf-tests:6.0.0-RC2]	
	at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createTestSecurityContext(WithSecurityContextTestExecutionListener.java:134) ~[security-thymeleaf-tests:6.0.0-RC2]	
	at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createTestSecurityContext(WithSecurityContextTestExecutionListener.java:113) ~[security-thymeleaf-tests:6.0.0-RC2]	
	at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.beforeTestMethod(WithSecurityContextTestExecutionListener.java:81) ~[security-thymeleaf-tests:6.0.0-RC2]	
	at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:294) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.test.context.junit.jupiter.SpringExtension.beforeEach(SpringExtension.java:174) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$2(TestMethodTestDescriptor.java:166) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$6(TestMethodTestDescriptor.java:202) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:202) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:165) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:132) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68) ~[security-thymeleaf-tests:5.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[na:na]	
	at java.base@17.0.5/java.util.ArrayList.forEach(ArrayList.java:1511) ~[security-thymeleaf-tests:na]	
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[na:na]	
	at java.base@17.0.5/java.util.ArrayList.forEach(ArrayList.java:1511) ~[security-thymeleaf-tests:na]	
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[na:na]	
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[security-thymeleaf-tests:1.9.1]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147) ~[na:na]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127) ~[na:na]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90) ~[na:na]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55) ~[na:na]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102) ~[na:na]	
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54) ~[na:na]	
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) ~[na:na]	
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95) ~[na:na]	
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91) ~[na:na]	
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60) ~[na:na]	
	at org.graalvm.junit.platform.NativeImageJUnitLauncher.execute(NativeImageJUnitLauncher.java:74) ~[na:na]	
	at org.graalvm.junit.platform.NativeImageJUnitLauncher.main(NativeImageJUnitLauncher.java:129) ~[na:na]	
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.test.context.support.WithMockUserSecurityContextFactory': Failed to instantiate [org.springframework.security.test.context.support.WithMockUserSecurityContextFactory]: No default constructor found	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1306) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1198) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:321) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createFactory(WithSecurityContextTestExecutionListener.java:170) ~[security-thymeleaf-tests:6.0.0-RC2]	
	... 55 common frames omitted	
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.test.context.support.WithMockUserSecurityContextFactory]: No default constructor found	
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83) ~[security-thymeleaf-tests:6.0.0-RC4]	
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1300) ~[security-thymeleaf-tests:6.0.0-RC4]	
	... 60 common frames omitted	
Caused by: java.lang.NoSuchMethodException: org.springframework.security.test.context.support.WithMockUserSecurityContextFactory.<init>()	
	at java.base@17.0.5/java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[security-thymeleaf-tests:na]	
	at java.base@17.0.5/java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754) ~[security-thymeleaf-tests:na]	
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:79) ~[security-thymeleaf-tests:6.0.0-RC4]	
	... 61 common frames omitted

To Reproduce
Run ./gradlew security:security-thymeleaf:nativeTest in the AOT smoke tests.

Expected behavior
@WithMockUser and other @With… annotations work in native tests.

I suspect that AOT processing needs to look for any @WithSecurityContext (meta-)annotations and add reflection hints for their factory.

Sample
https://github.com/spring-projects/spring-aot-smoke-tests/tree/c8628f7baa5aa1c894bfe4a17706d7cdd218509f/security/security-thymeleaf

Metadata

Metadata

Labels

in: testAn issue in spring-security-testtype: bugA general bug

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions