英文:
SpringBoot unit test not getting @Value correctely of a @Component autowired object
问题
I'm implementing a unit test that is very simple, it increments a counter of the Google Guava library CacheLoader and gets the value.
RateLimitTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RateLimitTestConfiguration.class)
public class RateLimitTest {
@Autowired
RateLimitFilter rateLimitFilter;
@Test
public void incrementCounter_whenGetCounter_existsKey_and_returnIncrementedValue() throws ExecutionException {
final int times = 10;
final String counterName = "TestCounter";
int i = 0;
for(i = 0; i < 10; i++) {
rateLimitFilter.getRequestCountPerApiKey().put(counterName,i);
}
Assert.assertNotNull(rateLimitFilter.getRequestCountPerApiKey().get(counterName));
Assert.assertEquals(Long.valueOf(times),Long.valueOf(rateLimitFilter.getRequestCountPerApiKey().get(counterName)));
}
}
So I have implemented a @Bean in the test context:
@Configuration
public class RateLimitTestConfiguration {
@Bean
public RateLimitFilter rateLimitFilter() {
return new RateLimitFilter();
}
}
This is the class of the normal application:
@Component
public class RateLimitFilter implements GatewayFilter {
final Logger LOGGER = LoggerFactory.getLogger(RateLimitFilter.class);
@Value("${throttling.request.rate.minute}")
private int MAX_REQUEST_PER_MINUTE;
private LoadingCache<String, Integer> requestCountPerApiKey;
// ....
public LoadingCache<String, Integer> getRequestCountPerApiKey() {
return requestCountPerApiKey;
}
}
In the application.yml
of tests, I've set:
throttling:
request:
rate:
minute: 5
And the test fails with this error:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "${throttling.request.rate.minute}"
Is there anything specific you'd like me to help with regarding this code?
英文:
I'm implementing a unit test that is very sample, it's increment a counter of google guava library CacheLoader and get the value.
RateLimitTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = RateLimitTestConfiguration.class)
public class RateLimitTest {
@Autowired
RateLimitFilter rateLimitFilter;
@Test
public void incrementCounter_whenGetCounter_existsKey_and_returnIncrementedValue() throws ExecutionException {
final int times = 10;
final String counterName = "TestCounter";
int i = 0;
for(i = 0; i < 10; i++) {
rateLimitFilter.getRequestCountPerApiKey().put(counterName,i);
}
Assert.assertNotNull(rateLimitFilter.getRequestCountPerApiKey().get(counterName));
Assert.assertEquals(Long.valueOf(times),Long.valueOf(rateLimitFilter.getRequestCountPerApiKey().get(counterName)));
}
}
So I has implemented a @Bean on tests context:
@Configuration
public class RateLimitTestConfiguration {
@Bean
public RateLimitFilter rateLimitFilter() {
return new RateLimitFilter();
}
}
This is the class of application normal:
@Component
public class RateLimitFilter implements GatewayFilter {
final Logger LOGGER = LoggerFactory.getLogger(RateLimitFilter.class);
@Value("${throttling.request.rate.minute}")
private int MAX_REQUEST_PER_MINUTE;
private LoadingCache<String,Integer> requestCountPerApiKey;
....
public LoadingCache<String, Integer> getRequestCountPerApiKey() {
return requestCountPerApiKey;
}
}
on the application.yml
of tests I've set:
throttling:
request:
rate:
minute: 5
And Test fails with error:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "${throttling.request.rate.minute}"
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:79)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1252)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 55 common frames omitted
Caused by: java.lang.NumberFormatException: For input string: "${throttling.request.rate.minute}"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:638)
at java.base/java.lang.Integer.valueOf(Integer.java:983)
at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:211)
at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115)
at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:429)
at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:402)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:155)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:73)
答案1
得分: 2
以下是翻译好的部分:
-
你可以简单地将
@ContextConfiguration(classes = RateLimitTestConfiguration.class)
替换为@SpringBootTest(classes = RateLimitTestConfiguration.class)
。仅适用于Spring Boot。 -
你可以手动向你的配置中添加
PropertySourcesPlaceholderConfigurer
bean(第一种方法会自动配置此bean,以及其他内容):
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
英文:
There are a lot of approaches to make it work. I'll give 2 of them:
- You can simply replace
@ContextConfiguration(classes = RateLimitTestConfiguration.class)
with@SpringBootTest(classes = RateLimitTestConfiguration.class)
. Works only with Spring Boot. - You can add
PropertySourcesPlaceholderConfigurer
bean manually to your configuration (the 1st approach configures this bean automatically among others):
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论