3

@Value is not working during JUnit Test when the application.yml is in another location.

FooServiceTest

@RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = { AppConfig.class })
    public class FooServiceTest {

EmailService in other module

public class EmailService {

    @Value("${aws.credentials.accessKey}")
    private String accessKey;

application.yml

aws:
  credentials:
    accessKey: XXXXXXXX
    secretKey: ZXXXXXXXXX

But I got:

Could not resolve placeholder 'aws.credentials.accessKey' in string value "${aws.credentials.accessKey}"

Even I added

-Dspring_config_location=/home/foo/other/location/config/
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
richersoon
  • 4,682
  • 13
  • 44
  • 74

3 Answers3

2

Standard Spring Boot locations

If you want spring-boot's application.properties to be loaded, you should launch the unit test with Spring Boot (using @SpringApplicationConfiguration):

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { AppConfig.class })
public class FooServiceTest {
    @Test
    public void test...        
}

The application.yml should be under /config or root in the classpath.

See Spring Doc:

SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:

  • A /config subdirectory of the current directory.
  • The current directory
  • A classpath /config package
  • The classpath root

Specify additional locations (exemple when executed from unit tests)

Normally, you could have used PropertySource, however even though it allows to load configuration files from other locations, it will not work for injected (@Value) properties.

You may however specify the spring.config.location environment variable in a static bloc:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { AppConfig.class })
public class FooServiceTest {
    static {
        //if the file is NOT in the classpath
        System.setProperty("spring.config.location", "file:///path/to/application.yml");

        //if the file is in the classpath
        //System.setProperty("spring.config.location", "classpath:/path/in/classpath/application.yml");
    }

    @Test
    public void test...
}

Run tests from Gradle

According to this you may do this:

$ gradle test -Dspring.config.location=file:///path/to/application.yaml

Or

$ SPRING_CONFIG_LOCATION=file:///path/to/application.yaml gradle test

Or add a task to define the systemProperty:

task extconfig {
    run { systemProperty "spring.config.location", "file:///path/to/application.yaml" }
}

test.mustRunAfter extconfig
Community
  • 1
  • 1
alexbt
  • 16,415
  • 6
  • 78
  • 87
0

if it externalized properties and want to include in runtime via command line

when you run include --spring.config.location=file:///location/application.yml

http://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html#howto-change-the-location-of-external-properties

kuhajeyan
  • 10,727
  • 10
  • 46
  • 71
0

Using constructor injection makes it easy to create immutable services and enables to test without SpringContext:

public class EmailService {

    private final String accessKey;`enter code here`

    @Autowired
    public EmailService(@Value("${aws.credentials.accessKey}") String accessKey) {
        this.accessKey = accessKey;
    }
}

public class FooTestWithoutSpringContext {

    private EmailService emailService;

    @Before
    public void init() {
        emailService = new EmailService("mockPropertyValue");
    }

    @Test
    public void testFoo() {
        emailService...
    }
}
Journeycorner
  • 2,474
  • 3
  • 19
  • 43