如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url
Posted
技术标签:
【中文标题】如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url【英文标题】:How to set urls with port of StubRunner from spring-cloud-contract in spring-cloud-gateway contract tests 【发布时间】:2022-01-23 05:40:15 【问题描述】:我有一个 spring 云网关应用程序,它将请求路由到另一个服务。另一个服务定义了合约,这些合约在测试中由 Spring Cloud Gateway 应用程序作为存根导入。
现在我想在我的网关中进行合同测试,这将消耗另一个服务的存根。问题是我不知道如何将StubRunnerPort
作为属性/环境注入,以便我的配置类可以选择它并相应地配置路由:
Api网关路由配置
@Configuration
class GatewayConfig
@Value("$subscriptions.url")
private String subscriptionsUrl;
@Autowired
private TokenRelayGatewayFilterFactory tokenFilterFactory;
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
http.csrf(ServerHttpSecurity.CsrfSpec::disable);
return http.build();
@Bean
RouteLocator routeLocator(final RouteLocatorBuilder routeLocatorBuilder)
return routeLocatorBuilder.routes()
.route("subscriptions", subscriptionsRoute())
.build();
private Function<PredicateSpec, Buildable<Route>> subscriptionsRoute()
return spec -> spec
.path("/subscriptions/**")
.filters(s -> s.filter(tokenFilterFactory.apply()).prefixPath("/v1"))
.uri(subscriptionsUrl);
还有测试课:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = PnApiGatewayApp.class)
@AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app:+:stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
@ActiveProfiles("test")
class SubscriptionSpec
private WebTestClient webClient;
@LocalServerPort
private int port;
@StubRunnerPort("io.mkrzywanski:subscription-app")
private int stubRunnerPort;
@Autowired
ConfigurableEnvironment environment;
@BeforeEach
void setup()
String baseUri = "http://localhost:" + port;
this.webClient = WebTestClient.bindToServer()
.responseTimeout(Duration.ofSeconds(10))
.baseUrl(baseUri).build();
@Test
void test()
String body = "\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[\"value\":\" Rainbow Six\"]";
var response = webClient.post()
.uri("/subscriptions")
.header("Authorization", "Bearer xxx")
.header("Content-type", MediaType.APPLICATION_JSON_VALUE)
.bodyValue(body)
.exchange()
.expectStatus().isCreated()
.expectBody(String.class)
.value(Matchers.equalTo("\"subscriptionId : \"6d692849-58fd-439b-bb2c-50a5d3669fa9\"\""));
理想情况下,我希望 subscriptions.url
属性集 after 配置存根运行器,但 before 我的网关配置由 Spring 选择,以便 url 重定向起作用。
我已经尝试使用ApplicationContextInitializer
,但是当初始化程序实例启动时,StubRunnerPort 似乎尚未配置。
所以问题是 - 如何获取存根运行器端口并使用它来将其注入其他服务 url,以便网关将请求路由到测试中的存根运行器?
【问题讨论】:
【参考方案1】:解决方案 1
这可以通过使用 application-test.yml
文件来实现,该文件具有使用替换的已定义 url 属性。 application-test.yml
文件。该方法描述为here:
subscriptions:
url: http://localhost:$stubrunner.runningstubs.io.mkrzywanski.subscription-app.port
这里stubrunner.runningstubs.io.mkrzywanski.subscription-app.port
将用作存根端口,因此可以替换它。无需更改配置。
解决方案 2(需要更多代码)
我通过创建一个测试配置使其工作,该配置扩展了包含 url 属性和 RouteLocator
配置并依赖于 batchStubRunner
bean 的配置:
@DependsOn("batchStubRunner")
@EnableAutoConfiguration
@Import(LoggingFilter.class)
class GatewayTestConfig extends GatewayConfig implements InitializingBean
@Autowired
ConfigurableEnvironment environment;
@Override
public void afterPropertiesSet()
this.subscriptionsUrl = "http://localhost:" + environment.getProperty("stubrunner.runningstubs.io.mkrzywanski.subscription-app.port");
这里的重点是:
配置仅在batchStubRunner
bean 可用后运行,因此可以在environment
中找到 StrubRunner 的端口
配置实现了InitializingBean
,所以我可以覆盖subscriptionsUrl
,它现在是父配置中的protected
subscriptionsUrl
被覆盖后 - 它可用于从父配置配置 RouteLocator
bean。
现在的测试是这样的:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = GatewayTestConfig.class)
@AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app:+:stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
@ActiveProfiles("test")
class SubscriptionSpec
private WebTestClient webClient;
@LocalServerPort
private int port;
@BeforeEach
void setup()
String baseUri = "http://localhost:" + port;
this.webClient = WebTestClient.bindToServer()
.responseTimeout(Duration.ofSeconds(10))
.baseUrl(baseUri).build();
@Test
void shouldRouteToSubscriptions()
String body = "\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[\"value\":\"Rainbow Six\"]";
webClient.post()
.uri("/subscriptions")
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
.header("Authorization", "Bearer xxx")
.header("Content-type", MediaType.APPLICATION_JSON_VALUE)
.bodyValue(body)
.exchange()
.expectStatus().isCreated()
.expectBody()
.jsonPath("$.subscriptionId").exists()
.jsonPath("$.subscriptionId").value(IsUUID.UUID());
【讨论】:
以上是关于如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url的主要内容,如果未能解决你的问题,请参考以下文章
Spring-Cloud-Gateway 创建的初始 Trace 都命名为“/”,无论路径如何
无法根据活动的 Spring 配置文件生成不同的 spring-cloud-gateway 路由
java学习---spring-cloud-gateway网关配置
spring-cloud-gateway使用https注意事项---设置证书和需要注意的问题
sentinal spring-cloud-gateway adapter(1.6)异常错误之@EnableCircuitBreaker