繁体   English   中英

使用@PostConstruct模拟类会导致初始化失败

[英]Mocking class with @PostConstruct causes initialization failure

我有一个看起来像这样的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在模拟时如何工作感兴趣。

请您能帮我找到以下问题的答案吗?

  1. @PostConstruct带注释的方法在模拟时如何工作?
  2. 就我而言,类A,B和C属于不同的包。 因此,我需要嘲笑他们。 3.1。 为什么仅仅嘲笑A还不够? 3.2。 为什么我应该了解A的内部结构,并同时模拟基础/相关类?

提前致谢!

如果在上下文加载之前进行模拟,则应该能够这样做。 像这样的东西

public static class ContextLoader extends GenericXmlContextLoader {
    @Override
    protected void customizeContext(GenericApplicationContext context) {
        super.customizeContext(context);
        // Add mock for A in context here
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM