我有一个配置类,下面的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> {
型
3条答案
按热度按时间r8xiu3jd1#
如果你使用的是纯Spring而不带 Boot ,你仍然可以有两个选择。
第一个是使用
Mockito
来模拟一个有问题的bean,例如:字符串
这是最简单的例子。如果您的bean被注入到您想要测试的另一个bean中,这将需要对测试进行额外的操作,例如使用
@InjectMocks
或更复杂的操作。第二种是使用测试上下文配置来更改bean创建代码,例如:
型
为了演示这些功能,我在我的github上推出了一个工作示例
6qqygrtg2#
一种选择是潜在地重写单元测试,使得它仅测试特定的类,即而不创建应用上下文。另一个建议是通过使用
@MockBean
注解将模拟的Subscriber
bean添加到测试应用程序上下文,例如字符串
复制自@MockBean JavaDoc:
当按类型注册时,上下文中匹配类型(包括子类)的任何现有单个bean都将被mock替换。
yqhsw0fo3#
当你运行一个单元测试时,Spring会尝试完全初始化一个程序上下文。但是有几种方法可以影响Spring的初始化。
第一种方法是使用
@MockBean
注解,例如:字符串
但是有很多事情你要考虑,例如。其他bean如何与mock bean交互。为了解决与此相关的一些问题,可以使用
Mockito
。第二种方法是使用
@TestConfiguration
,例如:型
如果您使用测试配置,您将能够执行任何您想要创建
Subscriber
bean的操作。但这种方式需要添加额外的配置:spring.main.allow-bean-definition-overriding=true
。您可以将这一行放在application.properties
中,该application.properties
可以放在测试资源中。选择是你的,这些方法中哪一种更适合。为了演示这些方法,我在我的github上推出了一个工作示例。