So the short of my problem is, I'm trying to make a graphql client library, and test to see that it's working. @LocalServerPort isn't becoming available until @Test in Junit 5 in my project. I can't quite repro this in a demo project, but I believe this project should work, as is

@SpringJUnitConfig
@SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
class ActuatorApplicationTest {

    @Autowired String url;

    @Test
    void port() {
        Assertions.assertNotNull( url );
    }

    @TestConfiguration
    static class Config {
        @Bean
        String url( @LocalServerPort int port ) {
            return "http://localhost:" + port;
        }
    }
}

This is my real code right now...

@Configuration
class ApolloConfig {

    @Bean
    @Profile( "!test" )
    static ApolloClient.Builder prodClient( @Value( "${phdb.endpoint}" ) String graphqlEndpoint ) {
        return ApolloClient.builder().serverUrl( graphqlEndpoint );
    }

    @Bean
    @Profile( "test" )
    static ApolloClient.Builder testClient(@Value( "${local.server.port}" ) int port ) {
        return ApolloClient.builder();
    }
}

failure is

 Unexpected exception during bean creation; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'local.server.port' in value "${local.server.port}"

Comment From: xenoterracide

as a side note, I don't understand the need for local.server.port why not just use server.port seems like the latter is what I'd generally expect, but because it's different I also have to make a double config.

Comment From: spencergibb

server.port on a RANDOM_PORT test is 0.

Comment From: xenoterracide

@spencergibb yes, but that's not right... and not really helpful to the problem... just saying it doesn't seem like a proper dependency injection since I can't use the same definition, and have to wire it twice.

https://github.com/spring-projects/spring-boot/blob/80da9cf5ebdc256c0b743fd0c34c451a368530aa/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/ServerPortInfoApplicationContextInitializer.java#L62-L66

this code seems really late in the startup process which is likely why my expectations aren't being met.

Comment From: wilkinsona

The port isn’t guaranteed to be known until the embedded container has started and bound its connector. You can inject it into a test class by which time the context will have been refreshed. Alternatively, if you need it earlier you can listen for the WebServerInitializedEvent. You can’t inject it into any component as the port is not known in time.

Comment From: xenoterracide

that also doesn't help andy... I need to set up a custom http client to talk to the server... what you're telling me is that it's impossible to do that, it shouldn't be impossible to do that.

Comment From: xenoterracide

you basically just said you can't inject jdbc into your repository/dao because even though we create it we don't know the port in time...

Comment From: wilkinsona

I haven't said it's impossible, just that your expectation about local.server.port isn't realistic. You hadn't really described what you're trying to do and it's hard to reverse engineer from a few code snippets.

We've solved what I think is a similar problem for the auto-configured TestRestTemplate using LocalHostUriTemplateHandler. You might want to take a look at that and use it as inspiration.

If you need further guidance, then please ask on Stack Overflow or Gitter.

Comment From: xenoterracide

I will try to clarify (and look at the link in a second), I have a hand crafted repo that talks to a graphql api-ed database... I want to inject the http client in this case is apollo. In order to test this I'm spinning up a fake graphql server in spring boot. However, in order to configure the client correctly, I need a valid URI, which means I need the port. The only documented way to get the port is with local.server.port but that doesn't work as I would expect most @Value's to work, seeing that it doesn't seem it can actually be injected.

@Component
class EMRRepoImpl implements EMRRepo {
    private final ApolloClient client;

    EMRRepoImpl( ApolloClient client ) {
        this.client = Objects.requireNonNull( client );
    }
````

my test (currently a little different as I've been debugging)

@ActiveProfiles("test") @SpringJUnitConfig @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT ) class EMRRepoTest {

private final EMRRepo repo;
private final ApolloClient.Builder builder;
private final Environment env;
@Autowired
EMRRepoTest( EMRRepo repo, ApolloClient.Builder builder, Environment env ) {
    this.repo = repo;
    this.builder = builder;
    this.env = env;
}

is expecting to inject the repo, and that needs to be autowired anyways because it's a component. Essentially the same position I'd be in if I wanted to inject `TestWebClient` instead of `WebClient`

**Comment From: knoobie**

I stumbled across this 'issue' as well - got it working if somebody needs it in the future.

```java
  @Lazy // allows for initialization after the server port is known
  @TestConfiguration(proxyBeanMethods = false)
  static classTestConfiguration {

    @Bean
    public YourClass yourBean(@Value("${local.server.port}") int port) {
      //...
    }
  }

Comment From: birnbuazn

Thx @knoobie! Awesome! @Lazy in combination with a @Configuration saved my day.

Comment From: kicktipp

I solved it with a kind of proxy bean

@Component
public class GraphQLClient {

    private ApolloClient apolloClient;
    private final Environment environment;

    public GraphQLClient(Environment environment) {
        this.environment = environment;
    }

    public ApolloClient getApolloClient() {
        if (apolloClient == null) {
            String port = environment.getProperty("local.server.port");
            initApolloClient(port);
        }
        return apolloClient;
    }

    public synchronized void initApolloClient(String port) {
        this.apolloClient = ApolloClient.builder()
                .serverUrl("http://localhost:" + port + "/graphql")
                .build();
    }

    public <D extends Operation.Data, T, V extends Operation.Variables> GraphQLCallback<T> graphql(Operation<D, T, V> operation) {
        GraphQLCallback<T> graphQLCallback = new GraphQLCallback<>();
        if (operation instanceof Query) {
            Query<D, T, V> query = (Query<D, T, V>) operation;
            getApolloClient()
                    .query(query)
                    .enqueue(graphQLCallback);
        } else {
            Mutation<D, T, V> mutation = (Mutation<D, T, V>) operation;
            getApolloClient()
                    .mutate(mutation)
                    .enqueue(graphQLCallback);

        }
        return graphQLCallback;
    }
}

Comment From: curiousconcept

As of today version of SB. The @Lazy with test configuration didn't work for me, it still wasn't able to resolve property. What worked is this neat trick, since we know that port is resolved within Junit5 test we can use MockBean to inject into our services expecting to use the port but configure it later during test startup:

    @LocalServerPort
    private int port;

    @MockBean
    PortProvider provider;

    @Test
    public void saveNewCustomer() throws IOException {

        doReturn(port).when(provider).getServerPort();

interface

public interface PortProvider {
    int getServerPort();
}

Real PortProvider:

@Component
public class PortProviderImpl implements PortProvider {

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

    public int getServerPort() {
        assertNotNull(serverPort);
        return serverPort;
    }
}