Spring Boot + Cloud | Zuul代理 | 集成测试

12

使用Spring Boot构建微服务时,可以很容易地编写广泛且可读性强的集成测试,并使用MockRestServiceServer模拟远程服务请求。

是否有一种方法可以使用类似的方法在ZuulProxy上执行额外的集成测试?我想要实现的是能够模拟ZuulProxy将转发到的远程服务器,并验证所有ZuulFitler的行为是否符合预期。但是,ZuulProxy正在使用Netflix的RestClient(似乎已经过时),该客户端自然不使用可以通过MockRestServiceServer重新配置的RestTemplate,而且我目前找不到一个好的方法来模拟代理请求的远程服务的响应。

我有一个负责处理API会话密钥创建并且将执行类似于API网关的微服务。使用Zuul代理进行转发到底层公开的服务,Zuul Filters会检测会话密钥是否有效。因此,集成测试将创建一个有效的会话,然后转发到一个虚假的终点,例如“integration/test”。

可以通过在@WebIntegrationTest上设置配置属性来指定“integration/test”是一个新的终点,我可以成功模拟所有通过RestTemplate处理的服务,但无法模拟Zuul转发。

达到模拟转发目标服务的最佳方法是什么?

2个回答

8

请查看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")));
    }
}

3
为了让这个工作,需要添加任何配置吗?我正在尝试做类似的事情,但是Zuul没有识别到这条路线。我得到了这个异常信息:Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: strategie。我猜想这是因为Zuul配置期望从服务发现服务器(在本例中为Eureka)获取信息,以将调用路由到正确的IP地址。 - Juan Vega

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/

在同一端口上运行的本地 Wiremock 将无法帮助您。我仍在尝试找到类似的集成测试,其中我可以模拟 Spring 中的 Bean,并读取 Zuul 代理在进行请求调用之前选择路由的 url


我认为配置系统的整个理念是能够设置“生产”配置的覆盖,并在测试期间将其指向本地主机模拟,而不是不同的域。否则,您将进入更多的端到端测试。因此,我不会说这是Wiremock的限制,而是可能需要不同方法的设置?例如,您可能希望为面向模拟服务器的集成测试使用不同的配置文件。 - Alexej Kubarev
@Dherik 这难道不是你在寻找的吗?只需要定义两个WireMockRule并分别对它们进行存根处理。http://wiremock.org/docs/junit-rule/ - VB_
@Dherik,你可以通过在application-test.yml中将URL设置为forward://service-test-A来绕过这个限制进行测试。 - bhantol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接