【问题标题】:Java Wiremock - mock external server during testingJava Wiremock - 在测试期间模拟外部服务器
【发布时间】:2018-04-18 17:33:08
【问题描述】:

假设应用程序依赖于外部服务器上的 REST 服务,http://otherserver.com。为了进行测试,我想在 JUnit 环境中模拟外部休息调用(通过 Wiremock)。启动一个单独的服务器既费时又不容易。使用 WiremockRule 看起来是正确的方向。创建模拟控制器不是一种优雅的方式,因为 Wiremock 可用。

例如得到(“http://otherserver.com/service3/”);

PS:我当然知道我可以通过 Mockito 模拟 REST 调用。

使用 Wiremock 模拟本地主机很容易。如何使用该代码来模拟其他服务器和服务?我从流行的 Baeldung 示例中复制了部分内容。

public class WireMockDemo {
    @Rule
    public WireMockRule wireMockRule = new WireMockRule();


    @Test
    public void wireMockTestJunitOtherServer() {
        try {
            // **this does not work...** 
            configureFor("otherserver.com", 8080);

            stubFor(get(urlPathMatching("/service2/.*"))
                    .willReturn(aResponse()
                            .withStatus(200)
                            .withHeader("Content-Type", "application/json")
                            .withBody("\"testing-library\": \"WireMock\"")));

            // Test via simple client
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpGet request = new HttpGet("http://otherserver:8080/service2/test");
            HttpResponse httpResponse = httpClient.execute(request);
            String stringResponse = convertHttpResponseToString(httpResponse);
            System.out.println( "Response = " + stringResponse);

            // Test via JUnit
            verify(getRequestedFor(urlEqualTo("/service2/wiremock")));
            assertEquals(200, httpResponse.getStatusLine().getStatusCode());
            assertEquals("application/json", httpResponse.getFirstHeader("Content-Type").getValue());
            assertEquals("\"testing-library\": \"WireMock\"", stringResponse);
        } catch( Exception e) {
            e.printStackTrace();
        }
    }

    // Support methods
    private String convertHttpResponseToString(HttpResponse httpResponse) throws IOException {
        InputStream inputStream = httpResponse.getEntity().getContent();
        return convertInputStreamToString(inputStream);
    }
    private String convertInputStreamToString(InputStream inputStream) {
        Scanner scanner = new Scanner(inputStream, "UTF-8");
        String string = scanner.useDelimiter("\\Z").next();
        scanner.close();
        return string;
    }
}

【问题讨论】:

    标签: java wiremock


    【解决方案1】:

    您的应用程序代码不应硬编码http://otherserver.com,它应该是可配置的。正常运行时应指向http://otherserver.com,在测试模式下运行时应指向http://localhost:<port>,其中<port> 是您启动Wiremock 服务器的位置(最好是动态的以避免端口冲突)

    【讨论】:

      【解决方案2】:

      TL;博士:

      不,你不能。

      WireMock 所做的是建立一个 Jetty 服务器来模拟您需要向其发送请求的远程服务器。但是,它不会更改您的 hosts 文件或 DNS 映射,并会自动将您对远程服务器的真实请求“重定向”到 localhost。在测试中你仍然需要向localhost发送请求。

      如果您使用的是 Spring Boot,您可以做的是在 maintest 包中创建两个 application.yml 文件(或另一个属性文件),具有相同的键结构,但 @ 中的值987654326@ 是您请求的真实 URL(如 http://example.com/api),而在 src/test/resources/application.yml 中您输入了 localhost/api


      顺便澄清一下,MockMvc 不是用于模拟您的应用程序所依赖的外部 3rd 方服务器请求,而是发送到应用程序端点的请求强>。在 MockMvc 测试中,您的应用程序是接收请求的人,但在 WireMock 测试中,您的应用程序会发送请求。

      一些工作示例:

      // configure static, class-level rule for all tests, like @BeforeClass.
      // this launches a Jetty server with configurations
      @ClassRule
      public static WireMockClassRule classRule = new WireMockClassRule(options().
              port(80).httpsPort(443));
      
      // Divide @ClassRule and @Rule,
      // to bypass JUnit limitation of "@Rule cannot be static"
      @Rule
      public WireMockClassRule rule = classRule;
      
      
      @Test
      public void shouldReturnGivenJson() throws Exception {
          // stubFor() also works; givenThat() is more TDD-ish
          givenThat(post(urlEqualTo("/service2/test")) // <----- note here: without host name
                  .willReturn(WireMock.aResponse()
                          .withStatus(HttpStatus.OK.value())
                          .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
                          .withBody("{\"status\":\"up\"}")));
          // .... your connection here
      

      我建议从urlEqualTo() 开始,不要乱用正则表达式。然后你进入urlMatching()

      另外,使用org.apache.http.util.EntityUtils 从响应中获取内容。这是处理响应的官方内置方式。并且,使用ResponseHandler 因为它会consume() 响应而无需手动清理资源。

      查看 HttpClient 文档了解更多详情。

      【讨论】:

        猜你喜欢
        • 2015-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 2019-02-17
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        相关资源
        最近更新 更多