Here is a working example:
@Component
public class QuotesClient {
private final WebClient webClient;
public QuotesClient(WebClient.Builder builder, @Value("${client.baseUrl}") String baseUrl) {
this.webClient = builder.baseUrl(baseUrl).build();
}
public JsonNode getData() {
return this.webClient
.get()
.retrieve()
.bodyToMono(JsonNode.class)
.block();
}
}
Using the WebClient.Builder is optional.
The corresponding test can look like the following:
class QuotesClientTest {
private QuotesClient quotesClient;
private MockWebServer server;
@BeforeEach
public void setup() {
this.server = new MockWebServer();
this.quotesClient = new QuotesClient(WebClient.builder(), server.url("/").toString());
}
@Test
public void test() {
server.enqueue(new MockResponse()
.setStatus("HTTP/1.1 200")
.setBody("{\"bar\":\"barbar\",\"foo\":\"foofoo\"}")
.addHeader("Content-Type", "application/json"));
JsonNode data = quotesClient.getData();
assertNotNull(data);
System.out.println(data);
}
}
If you are searching for a similar setup using WireMock, Spring Boot, and JUnit 5, take a look at the linked guide.
Answer from rieckpil on Stack OverflowSince Spring Framework 5.2.5 (Spring Boot 2.x) you can use DynamicPropertySource annotation which is quite handy.
Here is a complete example how you can use it with MockWebServer to bind the correct port:
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public abstract class AbstractIT {
static MockWebServer mockWebServer;
@DynamicPropertySource
static void properties(DynamicPropertyRegistry r) throws IOException {
r.add("some-service.url", () -> "http://localhost:" + mockWebServer.getPort());
}
@BeforeAll
static void beforeAll() throws IOException {
mockWebServer = new MockWebServer();
mockWebServer.start();
}
@AfterAll
static void afterAll() throws IOException {
mockWebServer.shutdown();
}
}
Here's a solution that's working from me. Spring Boot 2 & Spring-Webflux 5.3.30 using SpringBootTest
MyServiceClientTestConfig creates injected beans port and myServiceClient, where
- The port Integer bean is generated using Spring's TestSocketUtils.findAvailableTcpPort()
- MyServiceClient is a Spring service that uses WebClient and gets initialized with a base URL.
As documented we should not re-use a MockWebServer instance between tests so create it before each test using the port we found free at test initialization and shut it down after each test.
I suppose there is a slim chance that since I find the port once when Spring is initializing the application context and there are short periods of time where it is not in use by MockWebServer, before the first call to init and between tests, that another process could take the port but the odds of that happening during the lifetime of the test seem incredibly small.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyServiceClientTest {
private static final Logger LOG = LoggerFactory.getLogger(MyServiceClientTest.class);
private MockWebServer mockWebServer;
@Autowired
private MyServiceClient myServiceClient;
@Autowired
private Integer port;
@BeforeEach
void init() throws IOException {
assertNotNull(myServiceClient);
assertNotNull(port);
// MockWebServer not re-usable between tests
mockWebServer = new MockWebServer();
mockWebServer.start(port);
assertNotNull(mockWebServer);
assertEquals(port, mockWebServer.getPort());
}
@AfterEach
void cleanUp() throws IOException {
// MockWebServer not re-usable between tests
mockWebServer.shutdown();
}
@Test
public void placeholderTest1() {
LOG.info("Hello 1 {}", mockWebServer.getPort());
}
@Test
public void placeholderTest2() {
LOG.info("Hello 2 {}", mockWebServer.getPort());
}
@Configuration
static class MyServiceClientTestConfig {
@Bean
Integer getFreePort () {
// find a free port to use for this test
return TestSocketUtils.findAvailableTcpPort();
}
@Bean
MyServiceClient getMyServiceClient(Integer port) {
return new MyServiceClient(String.format("http://localhost:%d", port));
}
}
}