SpringBoot单元测试无法正确获取@Autowired对象的@Value值。

huangapple go评论83阅读模式
英文:

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 = &quot;TestCounter&quot;;
        int i = 0;
        for(i = 0; i &lt; 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(&quot;${throttling.request.rate.minute}&quot;)
    private int MAX_REQUEST_PER_MINUTE;

    private LoadingCache&lt;String,Integer&gt; requestCountPerApiKey;

    ....

public LoadingCache&lt;String, Integer&gt; 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 &#39;java.lang.String&#39; to required type &#39;int&#39;; nested exception is java.lang.NumberFormatException: For input string: &quot;${throttling.request.rate.minute}&quot;
    	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: &quot;${throttling.request.rate.minute}&quot;
    	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

以下是翻译好的部分:

  1. 你可以简单地将 @ContextConfiguration(classes = RateLimitTestConfiguration.class) 替换为 @SpringBootTest(classes = RateLimitTestConfiguration.class)。仅适用于Spring Boot。

  2. 你可以手动向你的配置中添加 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:

  1. You can simply replace @ContextConfiguration(classes = RateLimitTestConfiguration.class) with @SpringBootTest(classes = RateLimitTestConfiguration.class). Works only with Spring Boot.
  2. 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(&quot;application.yml&quot;));
	propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
	return propertySourcesPlaceholderConfigurer;
}

huangapple
  • 本文由 发表于 2020年7月28日 04:22:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/63122970.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定