我想用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' 豆:不满意依赖通过表达构造函数参数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();
所以前ConversionService
应用到BeanFactory
的@Value
注入正在发生的事情。没有bueno!
我发现似乎是一种解决方法:
@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());
}
}
这迫使初始化早些时候发生,但并不觉得自己是正确的解决方案(至少它没有记载这样)。
我哪里出错了? 春天4.3.0,春天引导1.4.0M3
编辑
而现在我发现另一种方式为它失败!未做相同的配置类实现EnvironmentAware
:
@Override
public void setEnvironment(Environment environment) {
((AbstractEnvironment) environment).setConversionService(conversionService());
}
我发现PropertySourcesPropertyResolver
使用错误的(默认)ConversionService
。这让我很生气!
引起:java.lang.IllegalArgumentException异常:在org.springframework.core.env无法转换值[PT15s]从源类型[字符串]为目标类型[时间] 。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)
谢谢,但这似乎并没有帮助。 –