Spring Boot + 云 | Zuul 代理 |集成测试
Posted
技术标签:
【中文标题】Spring Boot + 云 | Zuul 代理 |集成测试【英文标题】:Spring Boot + Cloud | Zuul Proxy | Integration testing 【发布时间】:2016-04-13 03:45:22 【问题描述】:当使用 Spring Boot 构建微服务时,它非常容易编写广泛且可读性强的集成测试,并使用 MockRestServiceServer
模拟远程服务请求。
有没有办法使用类似的方法对ZuulProxy
执行额外的集成测试?我想要实现的是能够模拟ZuulProxy
将转发到的远程服务器,并验证我所有的ZuulFitler
s 的行为是否符合预期。但是,ZuulProxy
正在使用来自 Netflix 的 RestClient
(似乎已弃用?),它自然不使用 RestTemplate
可以由 MockRestServiceServer
重新配置,我目前找不到模拟响应的好方法来自远程服务的代理请求。
我有一个微服务负责处理 API 会话密钥的创建,然后将类似于 API 网关。使用 Zuul Proxy 转发到底层暴露的服务,Zuul Filters 会检测 Session key 是否有效。因此,集成测试会创建一个有效的会话,然后转发到一个假端点,例如“集成/测试”。
可以通过在@WebIntegrationTest
上设置配置属性来指定“集成/测试”是一个新端点,我可以成功模拟所有通过RestTemplate
处理但不是Zuul 转发的服务。
实现模拟前向目标服务的最佳方法是什么?
【问题讨论】:
【参考方案1】:查看WireMock。我一直在使用它对我的 Spring Cloud Zuul 项目进行集成级别测试。
import static com.github.tomakehurst.wiremock.client.WireMock.*;
public class TestClass
@Rule
public WireMockRule serviceA = new WireMockRule(WireMockConfiguration.options().dynamicPort());
@Before
public void before()
serviceA.stubFor(get(urlPathEqualTo("/test-path/test")).willReturn(aResponse()
.withHeader("Content-Type", "application/json").withStatus(200).withBody("serviceA:test-path")));
@Test
public void testRoute()
ResponseEntity<String> responseEntity = this.restTemplate.getForEntity("/test-path/test", String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
serviceA.verify(1, getRequestedFor(urlPathEqualTo("/test-path/test")));
【讨论】:
是否需要添加任何配置才能使其正常工作?我正在尝试做类似的事情,但 Zuul 没有选择路线。我得到了这个异常Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: strategie
。我想这来自 Zuul 配置,期望来自服务发现服务器(在本例中为 Eureka)的信息,以将调用路由到正确的 ip。【参考方案2】:
接受的答案具有主要思想。但我在某些方面挣扎,直到找出问题所在。所以我想用 Wiremock 来展示一个更完整的答案。
测试:
@ActiveProfiles("test")
@TestPropertySource(locations = "classpath:/application-test.yml")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(port = 5001)
public class ZuulRoutesTest
@LocalServerPort
private int port;
private TestRestTemplate restTemplate = new TestRestTemplate();
@Before
public void before()
stubFor(get(urlPathEqualTo("/1/orders/")).willReturn(aResponse()
.withHeader("Content-Type", MediaType.TEXT_html_VALUE)
.withStatus(HttpStatus.OK.value())));
@Test
public void urlOrders()
ResponseEntity<String> result = this.restTemplate.getForEntity("http://localhost:"+this.port +"/api/orders/", String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(1, getRequestedFor(urlPathMatching("/1/.*")));
还有application-test.yml
:
zuul:
prefix: /api
routes:
orders:
url: http://localhost:5001/1/
cards:
url: http://localhost:5001/2/
这应该可行。
但是 Wiremock 对我有一些限制。如果您在不同端口上运行具有不同主机名的代理请求,如下所示:
zuul:
prefix: /api
routes:
orders:
url: http://lp-order-service:5001/
cards:
url: http://lp-card-service:5002/
在同一端口上运行的 localhost Wiremock 将无法为您提供帮助。我仍在尝试找到一个类似的集成测试,我可以在其中模拟来自 Spring 的 Bean,并阅读 Zuul 代理在发出请求调用之前选择的 url
路由。
【讨论】:
我认为配置系统的整个想法是能够为“生产”配置设置覆盖,并在测试期间将其指向 localhost 模拟而不是不同的域。否则,您正在研究更多的端到端测试。因此,我不会说这是 Wiremock 的限制,而是可能需要不同方法的设置?例如,您可能希望对模拟服务器的集成测试使用不同的配置文件 @Dherik 不是您要找的吗?只需定义两个WireMockRule
s 并将它们分别存根wiremock.org/docs/junit-rule
@Dherik 你应该能够通过使用 url 作为 forward://service-test-A
来解决这个限制,只是为了在 application-test.yml 中进行测试以上是关于Spring Boot + 云 | Zuul 代理 |集成测试的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot + 云 | Zuul 代理 |集成测试
Spring Boot - 无法通过 Zuul 代理获得 Keycloak 授权 api 的响应
Spring Boot 微服务 com.netflix.zuul.exception.ZuulException:转发错误