Java 库: Hoverfly 库


Hoverfly是一个轻量级服务虚拟化工具,允许您存根或模拟 HTTP(S) 服务。 Hoverfly Java 是一种本地语言绑定,它为您提供了一个用于在 Java 中管理 Hoverfly 的富有表现力的 API。它为您提供了一个抽象了二进制和 API 调用的 Hoverfly 类、一个用于创建模拟的 DSL 以及一个用于在单元测试中使用它的 JUnit 集成。

可以在不同的模式下执行测试,如模拟、间谍、捕获或差异。您可以使用 Java DSL 构建请求匹配器到响应映射。

让我们在 Maven 依赖项中包含最新版本的 Hoverfly:

<dependency>
  <groupId>io.specto</groupId>
  <artifactId>hoverfly-java-junit5</artifactId>
  <version>0.14.3</version>
</dependency>

假设我们的 Spring 中有以下方法@RestController。在为自己返回 ping 响应之前,它会调用 address 下的另一个服务http://callme-service:8080/callme/ping。

@GetMapping("/ping")
public String ping() {
   String response = restTemplate
     .getForObject("http://callme-service:8080/callme/ping", 
                   String.class);
   LOGGER.info("Calling: response={}", response);
   return "I'm caller-service " + version + ". Calling... " + response;
}

现在,我们将为我们的控制器创建测试。为了使用 Hoverfly 拦截传出流量:

  1. 我们注册了 HoverflyExtension。
  2. 然后我们可以使用 Hoverfly 对象来创建请求和模拟 HTTP 响应。

模拟的响应体是I'm callme-service v1。

@SpringBootTest(properties = {"VERSION = v2"}, 
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(HoverflyExtension.class) // (1)
public class CallerCallmeTest {
    
   @Autowired
   TestRestTemplate restTemplate;

   @Test
   void callmeIntegration(Hoverfly hoverfly) {
      hoverfly.simulate(
            dsl(service("http://callme-service:8080")
               .get("/callme/ping")
               .willReturn(success().body("I'm callme-service v1.")))
      ); // (2)
      String response = restTemplate
         .getForObject("/caller/ping", String.class);
      assertEquals("I'm caller-service v2. Calling... I'm callme-service v1.", response);
   }
}

我们可以通过@HoverflyConfig注解轻松定制Hovefly行为。默认情况下,Hoverfly在代理模式下工作。

假设我们希望它作为一个网络Web服务器,我们需要将属性webserver设置为true (1)。
之后,它将在localhost和proxyPort属性所指示的端口上监听请求。在下一步,我们还将启用Spring Cloud @LoadBalancedClient来配置目标URL的静态列表,而不是动态发现(2)。
最后,我们可以创建一个Hoverfly测试:这一次,我们将拦截来自监听在localhost:8080上的Web服务器的流量(3)。

@SpringBootTest(webEnvironment = 
   SpringBootTest.WebEnvironment.RANDOM_PORT)
@HoverflyCore(config = 
   @HoverflyConfig(logLevel = LogLevel.DEBUG, 
                    webServer = true, 
                    proxyPort = 8080)) // (1)
@ExtendWith(HoverflyExtension.class)
@LoadBalancerClient(name = "account-service", 
                    configuration = AccountServiceConf.class) // (2)
public class GatewayTests {

    @Autowired
    TestRestTemplate restTemplate;

    @Test
    public void findAccounts(Hoverfly hoverfly) {
        hoverfly.simulate(dsl(
            service("http://localhost:8080")
                .andDelay(200, TimeUnit.MILLISECONDS).forAll()
                .get(any())
                .willReturn(success("[{\"id\":\ŕ\",\"number\":\�\",\"balance\":5000}]", "application/json")))); // (3)

        ResponseEntity<String> response = restTemplate
                .getForEntity("/account/1", String.class);
        Assertions.assertEquals(200, response.getStatusCodeValue());
        Assertions.assertNotNull(response.getBody());
    }
}

下面是为测试目的而创建的负载均衡器客户端配置。

class AccountServiceInstanceListSuppler implements 
    ServiceInstanceListSupplier {

    private final String serviceId;

    AccountServiceInstanceListSuppler(String serviceId) {
        this.serviceId = serviceId;
    }

    @Override
    public String getServiceId() {
        return serviceId;
    }

    @Override
    public Flux<List<ServiceInstance>> get() {
        return Flux.just(Arrays
                .asList(new DefaultServiceInstance(serviceId + "1", 
                        serviceId, 
                        "localhost", 8080, false)));
    }
}