将 REST controller/route 添加到 Spring Boot 测试

Add REST controller/route to SpringBoot test

是否可以将 route/endpoint(我不想将其包含在源代码中,而是将其留在测试中)添加到 SpringBoot 测试中?

@RestController
class HelloAPI {
    @GetMapping("/hello")
    public String ok() {
        return "world";
    }
}

更新: 事实证明不需要额外的配置 - HelloAPI class 应该从 src/main 移动到 src/test。而已。但是,对于所有@SpringBoot 测试,它将是 "visible"。

所以问题是:如何将此 bean (HelloAPI) 的创建(在 ApplicationContext 中注册)限制为特定测试 class?

See link to an example project

您可以添加静态 inner @Configuration class 来设置 bean:

@RunWith(SpringRunner.class)
... // Other test annotations
public class YourTestClass {

    @Configuration
    static class ContextConfiguration {
        @Bean
        public HelloAPI helloAPI() {
            return new HelloAPI();
        }
    }

    @Test
    public void someTest_shouldXxx() { ... }
}

并确保在 /src/test 中添加 HelloAPI class 而不是 /src/main/

但是请注意,(test)ApplicationContext 将在执行完 class 中的所有测试后被销毁,从而也销毁 HelloAPI bean。

如果您正在寻找向 RestTemplate 提供 test-endpoints 的方法,请将 MockRestServiceServer 绑定到您的 RestTemplate instead.

您可以为此使用 @TestConfiguration

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = DEFINED_PORT)
class EmbeddedApiTest {

    @Test
    void testSomething() {
        ...
    }

    @TestConfiguration
    public static class TestCfg {

        @RestController
        @RequestMapping("/test")
        public class TestApi {

            @GetMapping("/hello")
            public String hello() {
                return "Hello World!";
            }
        }
    }
 }

虽然我已经接受了 Anatoliy 的回答(他正在使用 Java 和 JUnit5),但我想分享我的 Kotlin 代码(使用旧的 JUnit4):

@RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
class TestWithInnerConfigTest {
    @LocalServerPort var port: Int? = null
    @Autowired private lateinit var restTemplate: TestRestTemplate

    @Test
    fun testingMainEndpoint() {
        val url = "http://localhost:$port/helloworld"
        val resp = restTemplate.exchange(url, GET, null, String::class.java)
        assertEquals(resp.statusCode, OK)
    }

    @Test
    fun testingTestEndpoint() {
        val url = "http://localhost:$port/test"
        val resp = restTemplate.exchange(url, GET, null, String::class.java)
        assertEquals(resp.statusCode, NOT_FOUND)
    }

    companion object {
        @TestConfiguration
        class TestCfg {
            @RestController
            class TestApi {
                @GetMapping("/test") fun hello() = "Helloworld!"
            }
        }
    }
}

使用静态内部 @TestConfiguration class 的好处是它仅应用于此文件。这是 link to the complete example.