我有一个java程序,看起来像这样:
public abstract class AbstractA {
@Autowired
protected B b;
}
@Component
public class A extends AbstractA {
private C c;
@PostConstruct
public void initilizeC() {
c = b.getInternalMember();
}
}
@Component
public class D {
@Autowired
private A a;
}
@Component
public class E {
@Autowired
private D d;
}
我的测试类如下:
@ContextConfiguration(location = {"file:unit-test.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class ETest {
//class E(being tested) internally uses method of D
@Autowired
private A a;
@Test
public void methodOfETest() {
Mockito.when(a.methodOfC(anyInt())).thenReturn(1);
}
@After
public void resetMocks() {
Mockito.reset(a);
}
}
我的spring文件(仅捕获bean初始化)
<bead id="b" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg="classpath to B" />
</bean>
<bead id="a" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg="classpath to A" />
</bean>
由于以下异常,我的单元测试失败:
[junit] Failed to load ApplicationContext
[junit] java.lang.IllegalStateException: Failed to load ApplicationContext
[junit] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
[junit] at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
[junit] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
[junit] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
[junit] at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:230)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:249)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
[junit] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
[junit] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
[junit] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'e': Injection of autowired dependencies
failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: protected class-path.D class-path.E.d; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'd': Injection of autowired dependencies
failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private class-path.a class-path.d.a; nested exception
is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'a': Invocation of init method failed; nested
exception is java.lang.NullPointerException
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
[junit] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
[junit] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838)
[junit] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
[junit] at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125)
[junit] at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
[junit] at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109)
[junit] at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261)
[junit] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
[junit] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Could not
autowire field: protected class-path.D class-path.E.d; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'd': Injection of autowired dependencies
failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private class-path.a class-path.d.a; nested exception
is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'a': Invocation of init method failed; nested
exception is java.lang.NullPointerException
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
[junit] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'd': Injection of autowired dependencies
failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private class-path.a class-path.d.a; nested exception
is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'a': Invocation of init method failed; nested
exception is java.lang.NullPointerException
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
[junit] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private class-path.a class-path.d.a; nested exception
is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'a': Invocation of init method failed; nested
exception is java.lang.NullPointerException
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
[junit] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'a': Invocation of init method failed; nested
exception is java.lang.NullPointerException
[junit] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
[junit] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
[junit] Caused by: java.lang.NullPointerException
[junit] at class-path.A.initializeC(A.java:64)
[junit] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354)
[junit] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:305)
[junit] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
根据注释,我可以使用@Qualifier并使测试用例正常工作。但我仍然有兴趣了解@PostConstruct是如何在嘲笑的同时工作的。
你能帮我找到以下问题的答案吗?
- @PostConstruct带注释的方法在嘲讽时是如何工作的
- 在我的情况下,A类、B&C属于不同的包。因此,我需要嘲笑他们。3.1.为什么仅仅模仿A还不够?3.2.为什么我要理解A的内部结构,并模拟底层/依赖类
提前感谢!
如果在加载上下文之前进行mock,应该可以这样做。像这个
public static class ContextLoader extends GenericXmlContextLoader {
@Override
protected void customizeContext(GenericApplicationContext context) {
super.customizeContext(context);
// Add mock for A in context here
}
}