我想用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)
謝謝,但這似乎並沒有幫助。 –