【问题标题】:How to mock a web server for unit testing in Java? [closed]如何在 Java 中模拟 Web 服务器以进行单元测试? [关闭]
【发布时间】:2009-03-03 13:14:30
【问题描述】:

我想使用模拟 Web 服务器创建单元测试。是否有一个用 Java 编写的 Web 服务器,可以通过 JUnit 测试用例轻松启动和停止?

【问题讨论】:

  • 任务看起来更像是创建集成测试,而不是单元测试。
  • 如果您将“单元测试”理解为测试技术(“JUnit”)和质量(快速、无先决条件、测试用例隔离),而不是大小(仅测试一个单元),那么“集成测试”可以是“单元测试”。
  • 不知道为什么这个问题因为不符合 SO 准则而被关闭。对我来说,OP在这里问什么似乎很清楚。我们是否对这将是一个单元测试还是集成测试以及一个为测试目的而启动的真实 Web 服务器是否可以被视为一个模拟而争论不休?

标签: java junit


【解决方案1】:

Wire Mock 似乎提供了一组可靠的存根和模拟来测试外部 Web 服务。

@Rule
public WireMockRule wireMockRule = new WireMockRule(8089);


@Test
public void exactUrlOnly() {
    stubFor(get(urlEqualTo("/some/thing"))
            .willReturn(aResponse()
                .withHeader("Content-Type", "text/plain")
                .withBody("Hello world!")));

    assertThat(testClient.get("/some/thing").statusCode(), is(200));
    assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}

它也可以与 spock 集成。发现示例here

【讨论】:

  • 这对我来说效果很好。使用wireMockConfig().dynamicPort() 使其在其他程序可能使用该端口的设置中更具可预测性。我希望这是默认设置,因为我几乎错过了这种可能性并跳过了这个很棒的库。
  • @gribo 我想 testClient 是您正在测试的实际实例。
【解决方案2】:

您是否尝试使用mock or an embedded 网络服务器?

对于 mock 网络服务器,尝试使用 Mockito 或类似的东西,然后模拟 HttpServletRequestHttpServletResponse 对象,例如:

MyServlet servlet = new MyServlet();
HttpServletRequest mockRequest = mock(HttpServletRequest.class);
HttpServletResponse mockResponse = mock(HttpServletResponse.class);

StringWriter out = new StringWriter();
PrintWriter printOut = new PrintWriter(out);
when(mockResponse.getWriter()).thenReturn(printOut);

servlet.doGet(mockRequest, mockResponse);

verify(mockResponse).setStatus(200);
assertEquals("my content", out.toString());

对于嵌入式网络服务器,您可以使用Jetty,也可以使用use in tests

【讨论】:

    【解决方案3】:

    您也可以使用 JDK 的 com.sun.net.httpserver.HttpServer 类编写模拟(不需要外部依赖项)。请参阅this blog post 详细说明。

    总结:

    HttpServer httpServer = HttpServer.create(new InetSocketAddress(8000), 0); // or use InetSocketAddress(0) for ephemeral port
    httpServer.createContext("/api/endpoint", new HttpHandler() {
       public void handle(HttpExchange exchange) throws IOException {
          byte[] response = "{\"success\": true}".getBytes();
          exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length);
          exchange.getResponseBody().write(response);
          exchange.close();
       }
    });
    httpServer.start();
    
    try {
    // Do your work...
    } finally {
       httpServer.stop(0); // or put this in an @After method or the like
    }
    

    【讨论】:

    • 有没有办法断言HttpServer是否收到了请求?
    • 不应使用 com.sun.* 类。
    • @RamPatra 您可以在 Handler 类中跟踪它(他们要求什么等)
    • @TilmanHausherr com.sun.* 没问题。不应使用“sun.*”或“jdk.internal.*”。
    【解决方案4】:

    试试Simple(Maven) 它很容易嵌入到单元测试中。以 RoundTripTest 和用 Simple 编写的 PostTest 等示例为例。提供如何将服务器嵌入到您的测试用例中的示例。

    此外,Simple 比 Jetty 更轻、更快,并且没有依赖项。因此,您不必在类路径中添加多个 jar 文件。您也不必担心WEB-INF/web.xml 或任何其他工件。

    【讨论】:

    • 虽然这可能是用户想要的,但这不是“模拟”网络服务器,它是在单元测试中启动的实际网络服务器。例如,如果端口被占用,它将失败,所以不是真正的模拟(即确实有来自系统的外部依赖)。根据 Martin Fowler 对"Test Doubles" 的命名,这是一个“假”。也就是说,它正是我正在寻找的。​​span>
    • 这个项目倒闭了吗?
    【解决方案5】:

    另一个不错的选择是MockServer;它提供了一个流畅的界面,您可以使用该界面定义模拟 Web 服务器的行为。

    【讨论】:

    • MockServer 也依赖于 Netty(不是 Jetty)。
    【解决方案6】:

    您可以尝试Jadler,它是一个具有流畅的编程Java API 的库,可以在您的测试中存根和模拟http 资源。示例:

    onRequest()
        .havingMethodEqualTo("GET")
        .havingPathEqualTo("/accounts/1")
        .havingBody(isEmptyOrNullString())
        .havingHeaderEqualTo("Accept", "application/json")
    .respond()
        .withDelay(2, SECONDS)
        .withStatus(200)
        .withBody("{\\"account\\":{\\"id\\" : 1}}")
        .withEncoding(Charset.forName("UTF-8"))
        .withContentType("application/json; charset=UTF-8");
    

    【讨论】:

    • 我尝试使用 Jadler,但每当我尝试调用 initJadler() 时,我都会收到github.com/jadler-mocking/jadler/issues/107 中提到的错误。有什么想法可能出了什么问题?
    • 你能把 mvn dependency:tree 的结果粘贴到这里吗?这可能是图书馆的冲突。
    • 请阅读我在 github.com/jadler-mocking/jadler/issues/107 中的回答,这个问题是由 Jetty 版本(8 vs 9)的冲突引起的。您可以删除 Jetty9 依赖项(如果测试运行不需要它)或在没有 Jetty 依赖项的情况下运行 Jadler (github.com/jadler-mocking/jadler/wiki/…)
    • 这个框架似乎不支持 TestNG,请参阅github.com/jadler-mocking/jadler/issues/118
    • 错误报告因无法重现而关闭。您绝对可以将 Jadler 与 TestNG 一起使用。
    【解决方案7】:

    如果您使用的是 apache HttpClient,这将是一个不错的选择。 HttpClientMock

    HttpClientMock httpClientMock = new httpClientMock() 
    HttpClientMock("http://example.com:8080"); 
    httpClientMock.onGet("/login?user=john").doReturnJSON("{permission:1}");
    

    基本上,您然后对您的模拟对象发出请求,然后可以对其进行一些验证httpClientMock.verify().get("http://localhost/login").withParameter("user","john").called()

    【讨论】:

    【解决方案8】:

    尝试使用Jetty web server

    【讨论】:

    【解决方案9】:

    我推荐Javalin。它是模拟真实服务的绝佳工具,因为它允许在测试中进行状态断言(服务器端断言)。

    Wiremock 也可以使用。但这会导致难以维护行为测试(验证客户端调用是否符合预期)。

    【讨论】:

      【解决方案10】:

      为了完整起见,还使用camel 包裹了码头,使其更加用户友好。

      让你的测试类扩展 CamelTestSupport 然后定义一个路由 ex:

        @Override
        protected RouteBuilder createRouteBuilder() {
          return new RouteBuilder() {
            @Override
            public void configure() {
              from("jetty:http://localhost:" + portToUse).process(
                      new Processor() {
                        @Override
                        public void process(Exchange exchange) throws Exception {
                          // Get the request information.
                          requestReceivedByServer = (String) exchange.getIn().getHeader(Exchange.HTTP_PATH);
      
                          // For testing empty response
                          exchange.getOut().setBody("your response");
                          ....
      

      获取它的示例 maven 依赖项:

      <dependency> <!-- used at runtime, by camel in the tests -->
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-jetty</artifactId>
        <version>2.12.1</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-core</artifactId>
        <version>2.12.1</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>org.apache.camel</groupId>
        <artifactId>camel-test</artifactId>
        <version>2.12.1</version>
        <scope>test</scope>
      </dependency>
      

      【讨论】:

        猜你喜欢
        • 2017-06-25
        • 1970-01-01
        • 1970-01-01
        • 2015-11-29
        • 2013-04-01
        • 2011-03-12
        • 2020-02-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多