In any Spring Boot project, running multiple controller instances simultaneously in tests does not necessarily cause a port clash. This is because, in most cases, unit tests for controllers are typically run without needing to start a real web server or bind to an actual port. Spring Boot provides several tools and strategies to run controller tests in isolation, avoiding port clashes.
❓ How Multiple Controller Tests Run Simultaneously:
- Mocking Web Layer with
@WebMvcTest: - What it is: Spring Boot provides the
@WebMvcTestannotation to focus only on testing the web layer (i.e., controllers). When you use this annotation, Spring Boot doesn’t start the full application context or a real web server. Instead, it mocks the web layer and allows you to test individual controllers in isolation. - Why it works: Since no real server is started, there is no need for a real port, and thus no port clashes. You are essentially testing the controller’s functionality without having to bind it to a network port.
- Example:
```java
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired private MockMvc mockMvc; @Testpublic void testController() throws Exception {
mockMvc.perform(get(“/api/endpoint”))
.andExpect(status().isOk());
}
}
- **MockMvc:** The`MockMvc\` object simulates HTTP requests and allows testing the controller logic without starting an actual web server. 5. **Using `@SpringBootTest` with Mocking:** 6. **What it is:** When you need to load the full application context, including multiple components and controllers, you can use `@SpringBootTest`. By default, `@SpringBootTest` can start a real web environment (which would require a port). However, you can configure it to avoid using an actual port by setting it to a **mock environment**. 7. **How to configure it:** You can set `@SpringBootTest(webEnvironment = WebEnvironment.MOCK)` to run the tests in a mock environment without binding to any real port. 8. **Example:**```java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class QEatsControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testMultipleControllers() throws Exception {
mockMvc.perform(get(“/eats/endpoint1”))
.andExpect(status().isOk());
mockMvc.perform(get("/eats/endpoint2")) .andExpect(status().isOk());
}
}```
9. In-memory Servers for Integration Testing:
10. What it is: In cases where you want to run an actual server for integration testing but avoid port clashes, you can configure tests to use random ports. Spring Boot provides an option to run the server on a random port so that each test instance gets its own port, preventing port conflicts.
11. How to configure it: Use@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)to assign a random port to each test instance.
12. Example:```java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RandomPortIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testRandomPortServer() throws Exception {
String baseUrl = “http://localhost:” + port + “/api/endpoint”;
ResponseEntity response = restTemplate.getForEntity(baseUrl, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}```
- Random port: Each test runs on a random port, so no port clashes occur even if multiple instances of the server run concurrently.
13. Using@MockBeanto Avoid Actual Service Calls:
14. What it is: In addition to testing controllers, you often need to mock the dependencies they use, such as services or repositories. Spring Boot’s@MockBeanannotation allows you to mock beans so that your controller tests don’t depend on actual service or database interactions.
15. Example:```java
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private MyService myService;
@Test
public void testControllerWithMockService() throws Exception {
when(myService.getData()).thenReturn(new DataResponse());
mockMvc.perform(get("/api/endpoint")) .andExpect(status().isOk());
}
```
}
```
Summary:
In Spring Boot applications, you can run multiple controller tests without port clashes by using various techniques:
@WebMvcTest: Tests only the controller layer, without starting a real server or requiring a port.@SpringBootTestwithWebEnvironment.MOCK: Starts the full Spring context but without an actual web server, avoiding port clashes.@SpringBootTestwithWebEnvironment.RANDOM_PORT: Starts the server on a random port, ensuring no conflicts when running multiple instances.MockMvcand@MockBean: Simulate HTTP requests and mock dependencies without needing a running server.
Using these techniques, you can effectively test multiple controllers simultaneously without any issues related to port conflicts.