Skip to content

Instantly share code, notes, and snippets.

@silkentrance
Last active May 26, 2023 09:23
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save silkentrance/b5adb52d943555671a44e88356c889f8 to your computer and use it in GitHub Desktop.
Save silkentrance/b5adb52d943555671a44e88356c889f8 to your computer and use it in GitHub Desktop.
Spring Boot Open Feign Client Integration Testing
test:
url:
url: http://localhost:${server.port}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.util.SocketUtils;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
@EnableFeignClients
public class TestApplication {
public static void main(String... args) {
SpringApplication.run(TestApplication.class, args);
}
public static class TestApplicationInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Map<String, Object> properties = new HashMap<>();
properties.put("server.port", SocketUtils.findAvailableTcpPort());
MapPropertySource propertySource = new MapPropertySource("Random Defined Server Port", properties);
applicationContext.getEnvironment().getPropertySources().addFirst(propertySource);
}
}
}
# Testing Open Feign Clients With Spring Boot
Here is an alternative method for testing feign clients with randomly assigned server ports.
With this approach, no load balancer configuration is required.
Please note, that instead of `WebEnvironment.RANDOM_PORT` one has to use the `WebEnvironment.DEFINED_PORT`.
See the attached sources for more information.
## Some Background Information
While using `RANDOM_PORT` as the web environment to use with a `SpringBootTest` works just fine with the embedded server, e.g.
```
@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
```
The random port is assigned by Java NIO, which uses a native method to find an unused random port.
To achieve this, spring will set the server.port environment variable to 0.
And, as soon as the web server started, the port will be known and it will then be set as the `local.server.port`
environment variable, which then can be injected via for example `@LocalServerPort`.
The feign client configuration, especially the url, will have been initialized long before that, so the feign client
will use whatever value `server.port` was assigned to.
Existing methods of injecting the random server port into the feign client configuration mostly involve setting up a
ribbon configuration and similar such mechanisms. (see https://medium.com/swlh/spring-boot-how-to-unit-test-a-feign-client-in-isolation-using-only-service-name-4e0fc9e151a7)
These methods, however use the ribbon package which is soon to be deprecated as it gets replaced by other load balancers
such as eureka or the spring loadbalancer.
Also, for setting up a quick and dirty test these methods all require additional configuration overhead.
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "test", contextId = "test", url = "${test.url}", path = "/test")
public interface TestWebClient {
@GetMapping(value = "/", produces = "text/plain")
String hello();
}
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.core.env.Environment;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ContextConfiguration(classes = TestApplication.class, initializers = TestApplication.TestApplicationInitializer.class)
public class TestWebClientTest {
@Autowired
private TestWebClient webClient;
@LocalServerPort
private int port;
@Autowired
private Environment environment;
@Test
public void notatest() throws Exception {
System.out.println(port);
System.out.println(webClient.hello());
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.ResponseBody;
@RestController
@RequestMapping(value = "/test")
public class TestWebService
@GetMapping(value = {"", "/"}, produces = "text/plain")
@ResponseBody
public String hello() {
return "world";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment