Spring Boot测试目录放置APP_2模拟控制器及优化测试方案问询
Great questions! Let's break this down step by step to clean up your integration tests and avoid exposing test endpoints in production.
1. Can I Move App_2_Controller to the Test Directory?
Absolutely you can (and should!) move your App_2_Controller to the test directory. This is a best practice because test-specific code has no place in your production source tree—keeping them separate prevents accidental exposure of test endpoints and keeps your main codebase clean.
How to Do It:
- Create a matching package structure under
src/test/java(e.g., if your main controller is incom.yourpackage.controller, createsrc/test/java/com/yourpackage/controller). - Move
App_2_Controller.javainto this test-side package. - Ensure your test class can pick up this controller:
- If your test uses
@SpringBootTest, it will automatically scan packages starting from your mainApplicationclass. As long as the test-side controller is in the same (or sub-) package, Spring will detect it when running tests. - If the package structure differs, add
@Import(App_2_Controller.class)to yourHttpRequestTestto explicitly include the test controller.
- If your test uses
2. Better Alternatives to Configuration File URL Swaps
Using configuration files to switch URLs works, but there are more flexible, maintainable approaches that avoid cluttering your configs and better isolate tests. Here are two top options:
Option 1: Mock the RestTemplate Directly with @MockBean
Instead of spinning up a real controller to mock APP_2, you can mock the RestTemplate bean that ForwardController uses. This keeps your tests fast and avoids needing a running HTTP endpoint for the mock.
Modify your HttpRequestTest like this:
@RunWith(SpringRunner.class) @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class HttpRequestTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; // Mock the RestTemplate used by ForwardController @MockBean private RestTemplate mockRestTemplate; @Test public void greetingShouldReturnDefaultMessage() throws Exception { // Define the mock response for APP_2's /serve endpoint ResponseEntity<String> mockApp2Response = new ResponseEntity<>("Hello End of world", HttpStatus.OK); // Tell Mockito to return this response when exchange() is called with the APP_2 URL String app2Url = "app.com:9000/serve"; // Use the real URL here—no config swap needed! when(mockRestTemplate.exchange( eq(app2Url), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class) )).thenReturn(mockApp2Response); // Execute the test assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/", String.class)) .contains("Hello End of world"); } }
This way, you don't need the App_2_Controller at all—you're directly mocking the external HTTP call.
Option 2: Use WireMock for Realistic HTTP Mocking
If you want to simulate a real HTTP service (to test request headers, URL parameters, or response handling more accurately), WireMock is the perfect tool. It lets you spin up a temporary HTTP server that mimics APP_2's behavior.
Step 1: Add WireMock Dependency
Add this to your pom.xml (Maven):
<dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock-jre8</artifactId> <version>2.35.0</version> <scope>test</scope> </dependency>
Step 2: Configure WireMock in Your Test
@RunWith(SpringRunner.class) @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureWireMock(port = 9000) // Starts WireMock on port 9000 (matches APP_2's real port) public class HttpRequestTest { @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Autowired private Environment environment; @Test public void greetingShouldReturnDefaultMessage() throws Exception { // Define the stub for APP_2's /serve endpoint stubFor(get(urlEqualTo("/serve")) .willReturn(aResponse() .withBody("Hello End of world") .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); // Verify the test uses WireMock's URL (set via application-test.properties) assertThat(environment.getProperty(Constants.APP_2_URL)).isEqualTo("http://localhost:9000/serve"); // Execute the test assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/", String.class)) .contains("Hello End of world"); } }
Now set APP_2_URL=http://localhost:9000/serve in your application-test.properties—no need to touch production configs. WireMock will handle all requests to that URL during tests.
Bonus: If You Still Want to Use a Test Controller
If you prefer keeping the App_2_Controller approach but want to avoid config swaps, use Spring Profiles to enable it only in tests:
- Add
@Profile("test")toApp_2_Controller(though moving to test directory is still better):@Controller @Profile("test") public class App_2_Controller { // ... existing code ... } - Then set
APP_2_URL=http://localhost:${local.server.port}/app2Stubin your test properties to point to the local test controller.
Final Recommendations
- Always move test-specific controllers to the test directory—it keeps production code clean and avoids accidental exposure.
- For most cases,
@MockBeanis the simplest and fastest option if you don't need to test HTTP-level details. - Use WireMock when you need to simulate real HTTP interactions (e.g., testing request headers, status codes, or error handling).
内容的提问来源于stack exchange,提问作者shashantrika

