1

I am trying to override Spring @Value annotated property that has a default value in the test class.

@Configuration
public class MyConfig {
    @Value("${MAX_CONN:200}")
    private int maxConn;

    //more code here
}

@RunWith(SpringRunner.class)
@ContextConfiguration(classes={MyConfig.class, PropertySourcesPlaceholderConfigurer.class}, loader=AnnotationConfigContextLoader.class)
@TestPropertySource(properties = {
        "MAX_CONN=2"
})
public class SomeTest {
    //tests here
}

I'm using org.springframework.test.context.TestPropertySource annotation for the purpose (thanks for the advise). During the debug, I see that maxConn value is still 200. If the default value is removed from the original code @Value("${MAX_CONN}"), the maxConn value got overridden with 2. The default property can also be overridden by defining an environment variable. I wonder if there is a way to override the @Value annotated property that has a default value?

Note: Spring version - 4.3.13

anuta
  • 11
  • 1
  • 4
  • YOu can do it using `ReflectionTestUtils.setField()` – pvpkiran Feb 04 '18 at 14:18
  • @pvpkiran - Thanks, I learned it from the [link](https://stackoverflow.com/a/17355595/1664705) either. I just wonder if there is a more elegant way. – anuta Feb 04 '18 at 14:28
  • For `unit test` you do not have to initialize Spring, in case you do not test smth. Spring specific: like database working or MVC. – Oleg Cherednik Feb 04 '18 at 15:50
  • @oleg.cherednik - Finally, implementing "springless" unit tests with Mockito and ReflectionTestUtils. More code, much less time, no voodoos – anuta Feb 05 '18 at 09:40
  • @anuta But it saves much time within huge project and this approach is recommended by Spring team in their doc. – Oleg Cherednik Feb 05 '18 at 09:42

2 Answers2

1

enter image description here

Output with above run configuration

MyConfig{maxConn=100}

Process finished with exit code 0

SpringBootWebApplication.java

package com.test;

import com.test.service.MyConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {

    @Autowired
    MyConfig myConfig;


    public static void main(String[] args) throws Exception {
        SpringApplication app = new SpringApplication(SpringBootConsoleApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
        //SpringApplication.run(SpringBootConsoleApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(myConfig);
    }
}

MyConfig.java

package com.test.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyConfig {

    @Value("${MAX.CONN:200}")
    private int maxConn;

    @Override
    public String toString() {
        return "MyConfig{" +
                "maxConn=" + maxConn +
                '}';
    }
}

TestProperties.java

import com.test.SpringBootConsoleApplication;
import com.test.service.MyConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootConsoleApplication.class)
public class TestProperties {

    static {
        System.setProperty("MAX.CONN", "2");
    }

    @Autowired
    MyConfig myConfig;

    @Test
    public void testSequence() {
        //System.out.println(myConfig);
        //...
    }

}

Output with Test:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.9.RELEASE)

MyConfig{maxConn=2}

Process finished with exit code 0
Mahendra Kapadne
  • 426
  • 1
  • 3
  • 10
  • I have tried it with Spring boot 1.5.1 with SpringFramework 4.3.6. Let me try same thing with Spring boot 1.5.9 which will use Spring Framework 4.3.13 – Mahendra Kapadne Feb 05 '18 at 01:22
  • We don't use properties files, but environment variables – anuta Feb 05 '18 at 06:48
  • @anuta I have updated answer with usage of environment Variable. – Mahendra Kapadne Feb 05 '18 at 16:35
  • the issue is not resolved, because I need to override the property programmatically in the unit test itself. I decided not to use spring in the unit tests as mentioned in the comments to the question. – anuta Feb 10 '18 at 09:33
  • @anuta If you are not using spring during your test for code which is using spring annotations, then conceptually code is not tested for full coverage. Yeah you can test with powermock and mockito but not advisable for this case. – Mahendra Kapadne Feb 10 '18 at 09:45
0

For using properties in unit test cases, conventionally there are two ways,

1> You should have your own set of properties used for testing and file should be under your classpath (/src/test/resources ).

@PropertySource("classpath:application-test.properties ")

2> Another convention is to have property files with the same name on different classpaths. You load one or the other depending on whether you are running your tests or not.

Thus in a typically laid out application, it is:

src/test/resources/application.properties

and

src/main/resources/application.properties

and use it as

@PropertySource("classpath:application.properties ")
surya
  • 2,581
  • 3
  • 22
  • 34