1

I get a -1 value returned when trying to get the server.port property from application.yml in a test context.

I do black box testing of a Spring-bot app. Here's a test case:

@SpringApplicationConfiguration(TestConfiguration.class)
public class StartupTest extends AbstractTestNGSpringContextTests implements EnvironmentAware {

    private static Logger logger = LoggerFactory.getLogger(StartupTest.class);

    @Value("${server.port}")
    private String port;

    @Value("${project.name}")
    private String name;

    private RelaxedPropertyResolver propertyResolver;

    @Override
    public void setEnvironment(Environment environment) {
        this.propertyResolver = new RelaxedPropertyResolver(environment);
    }

    @Test
    public void isAppUpAndRunning() {
        logger.debug("port: " + port);
        logger.debug("name: " + name);
        logger.debug("value for project.name: " + propertyResolver.getProperty("project.name"));
        logger.debug("value for server.port: " + propertyResolver.getProperty("server.port"));
        logger.debug("value for server.servlet-path: " + propertyResolver.getProperty("server.servlet-path"));
    }
}

NB: TestConfiguration.class contains nothing but @Configuration

Output:

[DEBUG] com.project.StartupTest - Running with Spring Boot v1.3.3.RELEASE, Spring v4.2.5.RELEASE
[INFO] com.project.StartupTest - The following profiles are active: test
[INFO] com.project.StartupTest - Started StartupTest in 4.698 seconds (JVM running for 7.761)
[DEBUG] com.project.StartupTest - port: ${server.port}
[DEBUG] com.project.StartupTest - name: ${project.name}
[DEBUG] com.project.StartupTest - value for project.name: MyProject
[DEBUG] com.project.StartupTest - value for server.port: -1
[DEBUG] com.project.StartupTest - value for server.servlet-path: /

So there's actually 2 questions here:

  • why can't I get the properties injected with the @Value annotation?
  • why can I get all application.yml properties with a PropertyResolver but server.port ?

What I need ultimately is a convenient way to access all the application.yml properties in a 'classic' test (i.e. not a Spring integration test as I want to test the application as it is at runtime). I've tried using

@ContextConfiguration(classes = TestConfiguration.class, initializers = ConfigFileApplicationContextInitializer.class)

as well, but the problem remains the same.

coolnodje
  • 789
  • 1
  • 7
  • 20
  • You haven't told the testing infrastructure that you're running a web-based test. Try annotating your test class with `@WebIntegrationTest` – Andy Wilkinson Apr 12 '16 at 11:36
  • The thing is, I don't want to use `@WebIntegrationTest` because I don't need to start an embedded container, I don't want to start the application: I just need to run a Spring's RestTemplate to black box test my Rest layer. But I need to have access to the `application.xml` and the Spring profiles for this. And I do have access to all properties, all be it not with the convenient `@Value` annotation, but `server.port` or `local.server.port`. `management.port` for instance IS available. – coolnodje Apr 13 '16 at 02:56
  • If you want to black-box test using RestTemplate you will need spring boot to start up a Web server (otherwise what are you going to fire your requests at) and the spring-boot way to do this is using @WebIntegrationTest. If you just want to test your controller then the mvc test classes can do that by mocking the Dispatcher – Dave Bower Apr 13 '16 at 09:07
  • The web server is fired at Maven's integration-test phase, then I can run as many integration test as I want without having to restart a web server each time. This work very well, and is a clean way to separate "application" testing (including Unit test & Spring's WebIntegrationTest) and black box testing against a running server. These are all perfectly compatible and complementary. – coolnodje Apr 13 '16 at 09:26

3 Answers3

1

If you are not running an integration test, SpringApplicationContextLoader explicitly sets server.port to -1. A value of -1 disables the embedded servlet container, which is what you have asked for by not using @WebIntegrationTest.

Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • Right, that explains. I think my use case is a valid one though: I run black-box integration test during the Maven's `integration-test` phase which startup the spring-boot app with a chosen profile and let's me run as many test as I want without having to restart a web server for each of them. It's a complementary approach for me, I use Spring's WebIntegrationTest during unit testing AND black-box/integration test. This is perfectly fine and run all very well together. – coolnodje Apr 13 '16 at 09:34
  • It's only that I need to have access to the `application.yml` properties at test runtime, which I do thanks to `@SpringApplicationConfiguration` but then can't get the only property that apparently has a special status, and a very important one: `server.port` Do you feel it's a legitimate feature I could request? – coolnodje Apr 13 '16 at 09:34
  • Sorry, I don't really understand what you are trying to do. Note that `application.yml` isn't the only source of a property's value. You _are_ getting the value of `server.port`, it's just that it's been set to `-1` as you have told the test infrastructure that you do not want the embedded container to be started. That setting take precedences over whatever is in `application.yml` otherwise the embedded container would be started even though your test configuration is such that it should not be. – Andy Wilkinson Apr 13 '16 at 10:06
  • I mean there could be another way to avoid the startup of the embedded container. The choice of using this existing property `server.port` and to give it a special value for this purpose kind of breaks the property usage pattern. My use case which I believe is not an unusual one, using maven integration-test phase to startup the container, has to rely on the `server.port` property to know on which port the container is listening. Why not use a dedicated property for this, like `start.container` ? – coolnodje Apr 14 '16 at 09:55
1

I had the same issue, the @Value annotation in the integration test were not filling the properties with values (instead the placeholder ${..} was in there).

I 'solved' it for now by adding the PropertyPlaceholderAutoConfiguration.class to the @SpringApplicationConfiguration, ie:

@SpringApplicationConfiguration(TestConfiguration.class, PropertyPlaceholderAutoConfiguration.class)

However I'm not very happy with this so I opened a question on how to do this properly: Spring boot integration test with SpringApplicationConfiguration doesn't seem to resolve @Value annotation

Community
  • 1
  • 1
IHaanstra
  • 196
  • 1
  • 9
0

In test cases the running server's port is available in the local.server.port property:

@Value("${local.server.port}")
private int localServerPort;
Dave Bower
  • 3,487
  • 26
  • 28
  • Injecting properties with `@Value` is not working as I mentioned in the post. Besides `local.server.port` is not available either with a `PropertyResolver`. – coolnodje Apr 13 '16 at 03:05