Java Wiremock - 在测试期间模拟外部服务器

5
假设应用程序依赖于位于外部服务器http://otherserver.com上的REST服务。为了进行测试,我想在JUnit环境中模拟外部rest调用(通过Wiremock)。启动单独的服务器需要时间且不容易。使用WiremockRule似乎是正确的方向。创建模拟控制器并不是一种优雅的方式,因为可以使用Wiremock。

例如:get("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;
    }
}
2个回答

5

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


1

TL; DR:

不行。

WireMock的作用是建立一个Jetty服务器,模拟你需要发送请求的远程服务器。但它不会更改你的hosts文件或DNS映射,并自动将你真正的远程服务器的请求“重定向”到本地主机。在测试中,你仍然需要向localhost发送请求。

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


顺便说一下,为了澄清,MockMvc不是用于模拟你的应用程序所依赖的外部第三方服务器请求,而是用于发送到你的应用程序端点的请求。在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,因为它会自动清理资源而不需要手动清理。
请查阅HttpClient文档以获取更多详细信息。

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