【问题标题】:Spring Boot test case doesn't use custom conversion serviceSpring Boot 测试用例不使用自定义转换服务
【发布时间】:2016-10-23 11:00:54
【问题描述】:

我正在尝试使用 Spring Boot Test 编写一个集成测试用例。

我自定义了ConversionService 以了解新的java.time 类型:

@Configuration
public class ConversionServiceConfiguration {
    @Bean
    public static ConversionService conversionService() {
        final FormattingConversionService reg = new DefaultFormattingConversionService();
        new DateTimeFormatterRegistrar().registerFormatters(reg);
        return reg;
    }
}

然后期待它工作:

@Component
class MyServiceConfig {
    @Value("${max-watch-time:PT20s}")
    private Duration maxWatchTime = Duration.ofSeconds(20);
}

在正常的SpringApplication.run 下运行时,这似乎工作正常。但是,在我的测试用例中:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes= {
    MyServiceMain.class,
    AttachClientRule.class
})
public class MyTest {
    @Inject
    @Rule
    public AttachClientRule client;

    @Test(expected=IllegalArgumentException.class)
    public void testBad() throws Exception {
        client.doSomethingIllegal();
    }
}

它爆炸了:

原因:org.springframework.beans.factory.UnsatisfiedDependencyException:创建名为“AttachClientRule”的bean时出错:通过构造函数参数0表示的不满足依赖关系:

创建名为“MyServiceConfig”的 bean 时出错:通过字段“maxWatchTime”表达的不满足依赖关系:无法将类型 [java.lang.String] 的值转换为所需类型 [java.time.Duration];

嵌套异常是 java.lang.IllegalStateException:无法将类型 [java.lang.String] 的值转换为所需类型 [java.time.Duration]:找不到匹配的编辑器或转换策略;

深入研究进行实际转换的TypeConverterDelegate 的内部,它似乎捕捉到了DefaultListableBeanFactory 字段中使用的ConversionService。在设置该字段的位置设置观察点,我找到 AbstractApplicationContext.refresh() 方法:

// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();  // <--- MyServiceConfig initialized here
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // <--- DefaultListableBeanFactory.conversionService set here!!!
// Last step: publish corresponding event.
finishRefresh();

所以@Value 注入发生在ConversionService 应用于BeanFactory 之前。没有布宜诺!

我发现似乎是一种解决方法:

@Configuration
public class ConversionServiceConfiguration implements BeanFactoryPostProcessor {
    @Bean
    public static ConversionService conversionService() {
        final FormattingConversionService reg = new DefaultFormattingConversionService();
        new DateTimeFormatterRegistrar().registerFormatters(reg);
        return reg;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.setConversionService(conversionService());
    }
}

这会强制提前进行初始化,但感觉不是正确的解决方案(至少没有这样记录)。

我哪里做错了? Spring 4.3.0,Spring Boot 1.4.0M3

编辑

现在我发现了另一种失败的方法!不让同一个配置类实现EnvironmentAware:

@Override
public void setEnvironment(Environment environment) {
    ((AbstractEnvironment) environment).setConversionService(conversionService());
}

我发现PropertySourcesPropertyResolver 使用了错误的(默认)ConversionService。这让我发疯了!

原因:java.lang.IllegalArgumentException:无法将值 [PT15s] 从源类型 [String] 转换为目标类型 [Duration] 在 org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:94) 在 org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:65) 在 org.springframework.core.env.AbstractPropertyResolver.getProperty(AbstractPropertyResolver.java:143) 在 org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:546) 在 com.mycorp.DoSomething.go(DoSomething.java:103)

【问题讨论】:

    标签: java spring spring-boot dependency-management


    【解决方案1】:

    Spring Boot 开发人员已确认这是文档不完整且无法按规定工作:https://github.com/spring-projects/spring-boot/issues/6222

    【讨论】:

      【解决方案2】:

      尝试从conversionService bean 定义中删除static 关键字。

      【讨论】:

      • 谢谢,但这似乎没有帮助。
      猜你喜欢
      • 1970-01-01
      • 2021-05-04
      • 1970-01-01
      • 2014-10-25
      • 2015-08-02
      • 2015-05-21
      • 2021-03-15
      • 1970-01-01
      相关资源
      最近更新 更多