如何解决java.lang.IllegalStateException:无法加载ApplicationContext错误

rn0zuynd  于 2023-08-01  发布在  Java
关注(0)|答案(3)|浏览(209)

我有一个配置类,下面的bean创建在

@Bean
public Subscriber consumeMessage() {
    LOGGER.debug( "Subscriber bean created" );
    //here is some custom logic and as it does not find actual credential file its giving error and failed to create bean at app start.

    return subscriber;
}

字符串
看起来spring在运行单元测试之前试图创建和加载所有bean,并且由于一些业务逻辑,上面的bean创建失败。
注意:它的纯Spring应用程序不是spring-boot

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:145) [spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:515) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:217) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:144) [testng-6.10.jar:na]
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:169) [testng-6.10.jar:na]
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108) [testng-6.10.jar:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_362]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_362]
    at java.lang.Thread.run(Thread.java:750) [na:1.8.0_362]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'consumeMessage' defined in com.teams.docu.config.GcpPubSubConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.google.cloud.pubsub.v1.Subscriber]: Factory method 'consumeMessage' threw exception; nested exception is BusinessServiceException [details=ExceptionDetails [type=AUTHENTICATION_EXCEPTION, severity=ERROR, errorcode=gcp.credentials.read.error, args=null, validationErrors=null, namedParameters=[]]]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:243) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    ... 18 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.google.cloud.pubsub.v1.Subscriber]: Factory method 'consumeMessage' threw exception; nested exception is BusinessServiceException [details=ExceptionDetails [type=AUTHENTICATION_EXCEPTION, severity=ERROR, errorcode=gcp.credentials.read.error, args=null, validationErrors=null, namedParameters=[]]]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    ... 36 common frames omitted
Caused by: com.teams.docu.exception.BusinessServiceException: GCP Credential cannot be created from the stream
    at com.teams.docu.service.util.GCPUtil.getGoogleCredentials(GCPUtil.java:89) ~[classes/:na]
    at com.teams.docu.config.GcpPubSubConfiguration.getSubscriber(GcpPubSubConfiguration.java:54) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    ... 37 common frames omitted
Caused by: java.io.FileNotFoundException: dummyFileLocation (No such file or directory)
    at java.io.FileInputStream.open0(Native Method) ~[na:1.8.0_362]
    at java.io.FileInputStream.open(FileInputStream.java:195) ~[na:1.8.0_362]
    at java.io.FileInputStream.<init>(FileInputStream.java:138) ~[na:1.8.0_362]
    at java.io.FileInputStream.<init>(FileInputStream.java:93) ~[na:1.8.0_362]
    at com.teams.docu.service.util.GCPUtil.getGoogleCredentials(GCPUtil.java:87) ~[classes/:na]
    ... 49 common frames omitted


如何在运行单元测试时跳过/模拟Spring中的@Configuration类@Bean创建。
更新:我已经尝试了@ContextConfiguration,下面是我可以更新的测试类

@ContextConfiguration(classes = GcpPubSubConfig.class)
public class ServiceImplTest
    extends AbstractTestService<TService> {
}


下面是我们在编写单元测试时使用的框架/公共类,我不能更改。

@ContextConfiguration(locations = {
    "classpath:docu-service.xml"
})
public abstract class AbstractTestService<T>
    extends AbstractTestNGSpringContextTests {


}
但是由于我们正在使用的框架(AbstractTestService)已经使用了带有位置的@ContextConfiguration,因此出现以下错误

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:145) [spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:515) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:217) [testng-6.10.jar:na]
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:144) [testng-6.10.jar:na]
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:169) [testng-6.10.jar:na]
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108) [testng-6.10.jar:na]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_362]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_362]
    at java.lang.Thread.run(Thread.java:750) [na:1.8.0_362]
Caused by: java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader supports loading an ApplicationContext from [MergedContextConfiguration@7ea731f8 testClass = ServiceImplTest, locations = '{classpath:docu-service.xml}', classes = '{class com.docu.analytic.service.impl.GcpPubSubConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]: declare either 'locations' or 'classes' but not both.
    at org.springframework.util.Assert.state(Assert.java:94) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:233) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117) ~[spring-test-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    ... 18 common frames omitted
Tests run: 5, Failures: 1, Errors: 0, Skipped: 4, Time elapsed: 2.019 sec <<< FAILURE! - in com.docu.analytic.service.impl.ServiceImplTest
springTestContextPrepareTestInstance(com.docu.analytic.service.impl.ServiceImplTest)  Time elapsed: 1.955 sec  <<< FAILURE!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader supports loading an ApplicationContext from [MergedContextConfiguration@7ea731f8 testClass = ServiceImplTest, locations = '{classpath:docu-service.xml}', classes = '{class com.docu.analytic.service.impl.GcpPubSubConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]: declare either 'locations' or 'classes' but not both.


更新:我已经更新了我的测试类如下,我能够解决**“声明'locations'或'classes',但不是两者”**错误

@Import(GcpPubSubConfig.class)
public class ServiceImplTest
    extends AbstractTestService<GreenButtonConnectService> {

r8xiu3jd

r8xiu3jd1#

如果你使用的是纯Spring而不带 Boot ,你仍然可以有两个选择。
第一个是使用Mockito来模拟一个有问题的bean,例如:

@ExtendWith(MockitoExtension.class)
@ContextConfiguration(classes = {/** your configuration class **/})
class SomeTest {

    @Mock
    private Subscriber subscriber;
    
    // tests are here
}

字符串
这是最简单的例子。如果您的bean被注入到您想要测试的另一个bean中,这将需要对测试进行额外的操作,例如使用@InjectMocks或更复杂的操作。
第二种是使用测试上下文配置来更改bean创建代码,例如:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {/** your configuration class **/, SomeTest.TestConfiguration.class})
class SomeTest {

    @Configuration
    public static class TestConfiguration {

        @Bean
        public Subscriber consumeMessage() {
            // some dummy test building logic is here
            return subscriber
        }
    }

    @Autowired
    private Subscriber subscriber;

    // tests are here
}


为了演示这些功能,我在我的github上推出了一个工作示例

6qqygrtg

6qqygrtg2#

一种选择是潜在地重写单元测试,使得它仅测试特定的类,即而不创建应用上下文。另一个建议是通过使用@MockBean注解将模拟的Subscriber bean添加到测试应用程序上下文,例如

@MockBean
Subscriber subscriberMock;

字符串
复制自@MockBean JavaDoc:
当按类型注册时,上下文中匹配类型(包括子类)的任何现有单个bean都将被mock替换。

yqhsw0fo

yqhsw0fo3#

当你运行一个单元测试时,Spring会尝试完全初始化一个程序上下文。但是有几种方法可以影响Spring的初始化。
第一种方法是使用@MockBean注解,例如:

@SpringBootTest
class SomeTest {

    @MockBean
    private Subscriber subscriber;
    
    // tests are here
}

字符串
但是有很多事情你要考虑,例如。其他bean如何与mock bean交互。为了解决与此相关的一些问题,可以使用Mockito
第二种方法是使用@TestConfiguration,例如:

@SpringBootTest
class SomeTest {

    @TestConfiguration
    public static class CustomConfiguration {
    
        @Bean
        public Subscriber consumeMessage() {
            // some dummy test building logic is here
            return subscriber
        }
    }
    
    @Autowired
    private Subscriber subscriber;
    
    // tests are here
}


如果您使用测试配置,您将能够执行任何您想要创建Subscriberbean的操作。但这种方式需要添加额外的配置:spring.main.allow-bean-definition-overriding=true。您可以将这一行放在application.properties中,该application.properties可以放在测试资源中。
选择是你的,这些方法中哪一种更适合。为了演示这些方法,我在我的github上推出了一个工作示例。

相关问题