java - Spring 中 @Autowired 的替代方案,它不会在测试类设置之前初始化 bean

标签 java spring junit spring-test dbunit

我有一个与数据库通信的 Spring Bean 类,我正在为它编写一个测试用例。

我正在使用 DbUnit,它使用 JUnit 注释 @Before 设置内存数据库(基于扩展 DbUnit 基类)。

问题出在我尝试测试的@Autowired bean:它在其@Postconstruct 方法中访问数据库,这发生在数据库设置之前,请注意类本身用 @Component 注释。

因此,我需要一种方法或注释来使用,以便我正在测试的 bean 仅在 @Before JUnit 方法运行后才被初始化。

最佳答案

这是 spring 的常见问题,并且有解决它的通用解决方案。 你需要 build 所谓的“三期 build ”。

通常,您只想在设置所有 spring 上下文(使用数据库)后才初始化 bean。因此,您需要监听 spring 何时初始化,然后执行您的逻辑。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PostProxy {
}

此类应在您的上下文中定义为一个 bean。

public class PostProxySpringContextListener implements ApplicationListener<ContextRefreshedEvent> {

private static Logger LOG = LoggerFactory.getLogger(PostProxySpringContextListener.class);

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    String[] beanDefinitionNames = context.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        String originalClassName = getOriginalClassName(beanDefinitionName, event);
        if (originalClassName != null) {
            invokeAnnotatedMethods(context, beanDefinitionName, originalClassName);
        }
    }
}

private String getOriginalClassName(String name, ContextRefreshedEvent event) {
    try {
        ConfigurableListableBeanFactory factory =
                (ConfigurableListableBeanFactory)event.getApplicationContext().getAutowireCapableBeanFactory();
        BeanDefinition beanDefinition = factory.getBeanDefinition(name);
        return beanDefinition.getBeanClassName();
    } catch (NoSuchBeanDefinitionException e) {
        LOG.debug("Can't get bean definition for : " + name);
        return null;
    }
}

private void invokeAnnotatedMethods(ApplicationContext context, String beanDefinitionName, String originalClassName) {
    try {
        Class<?> originalClass = Class.forName(originalClassName);
        Method[] methods = originalClass.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(PostProxy.class)) {
                LOG.info("Executing @PostProxy annotated initialization method: " + method.toString());
                Object bean = context.getBean(beanDefinitionName);
                Method currentMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
                currentMethod.invoke(bean);
            }
        }
    } catch (ClassNotFoundException e) {
        LOG.trace("No class instance for bean " + beanDefinitionName + " with class name " + originalClassName);
    } catch (NoSuchMethodException e) {
        LOG.error("Error finding @PostProxy method for bean " + beanDefinitionName, e);
    } catch (InvocationTargetException e) {
        LOG.error("Error invoking @PostProxy method for bean " + beanDefinitionName, e);
    } catch (IllegalAccessException e) {
        LOG.error("Can't invoke annotated method in bean" + beanDefinitionName + " with class name " + originalClassName
                + ". Please check access modifiers on @PostProxy methods.", e);
    }
}
}

关于java - Spring 中 @Autowired 的替代方案,它不会在测试类设置之前初始化 bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35989118/

相关文章:

java - 如何使冰居中 :confirmationPanel within a modal ice:panelPopup (ICEfaces)?

Java - boolean 方法总是返回 false

java - Spring Security 如何在不登录的情况下更新 userDetails

spring - 向 Spring Data Rest 端点返回的对象添加字段?

scala - 动态加载后,A 类无法转换为 A 类

java - 尝试在 junit 中模拟 X500Principal 时出现 LinkageError

java - 对长类型检测的疑问

java - 在 Android 上拍照时发生崩溃。为什么?

java - Spring Controller 在 10 秒后做一些工作

java - JUnit 测试——是什么让它比手动测试更有用?