如何在 spock 框架中模拟 HttpURLConnection 及其 responseCode

How to mock HttpURLConnection and its responseCode in spock framework

我正在使用 Java 并在 groovy 中使用 spock 框架编写 junit,想要模拟 HttpUrlConnection 并根据不同情况设置 connection.getResponseCode() >> 200。

URL url = new URL(proxySettingDTO.getTestUrl());
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
...
LOGGER.debug("Response code ::{} ",connection.getResponseCode()); //200 or 403

我试过使用

HttpURLConnection httpURLConnection = Mock()
URL url = new URL(proxySettingDTO.getTestUrl());
url.openConnection(_) >> httpURLConnection

但它不起作用。

你的问题有几处错误:

  1. 它由一组不连贯的不完整代码片段组成,而不是 MCVE,即一个完整的、最小的示例,每个想要帮助您的人都可以编译和 运行没有做你的工作和自己编造例子 classes。那是你的工作。

  2. url.openConnection(_) >> httpURLConnection 中,您试图存根方法结果,但您的 URL 对象未声明为模拟、存根或间谍。也就是说,你的尝试注定要失败。

  3. 即使您尝试模拟 URL,JDK class 也是最终的,即您不能模拟它,因为模拟是子classes.

  4. 正在测试的 class 通过调用 url.openConnection(proxy) 获取 HttpURLConnection。由于 (3),该方法不可模拟,因此您应该将连接创建外部化到辅助程序 class ConnectionManager 中,然后将模拟实例注入被测 class 以进行它可测试。

一般来说,测试是一种设计工具,而不仅仅是用测试覆盖代码。如果测试困难,则意味着组件设计耦合太紧。让测试帮助使用 TDD(test-driven 开发)或至少 test-driven 重构来推动您的设计,即使后者有点晚并且意味着返工。如果你更多地解耦你的组件,例如通过不创建你的 class 内部依赖的对象实例,但允许 API 用户注入它们,例如通过构造函数或设置器,可测试性更好,你也更少头疼。

这个怎么样?

class UnderTest {
  private Proxy proxy
  private ProxySettingDTO proxySettingDTO
  private ConnectionManager connectionManager
   UnderTest(Proxy proxy, ProxySettingDTO proxySettingDTO, ConnectionManager connectionManager) {
    this.proxy = proxy
    this.proxySettingDTO = proxySettingDTO
    this.connectionManager = connectionManager
  }

  int getConnectionResponseCode() {
    URL url = new URL(proxySettingDTO.getTestUrl())
    HttpURLConnection connection = (HttpURLConnection) connectionManager.openConnection(url, proxy)
    connection.setRequestMethod("GET")
    connection.setUseCaches(false)
    connection.getResponseCode()
  }
}
class ProxySettingDTO {
  String getTestUrl() {
    "https://scrum-master.de"
  }
}
class ConnectionManager {
  URLConnection openConnection(URL url, Proxy proxy) {
    url.openConnection(proxy)
  }
}
package de.scrum_master.Whosebug.q71616286

import spock.lang.Specification

class HttpConnectionMockTest extends Specification {
  def test() {
    given: "a mock connection manager, returning a mock connection with a predefined response code"
    ConnectionManager connectionManager = Mock() {
      openConnection(_, _) >> Mock(HttpURLConnection) {
        getResponseCode() >> 200
      }
    }

    and: "an object under test using mock proxy, real DTO and mock connection manager"
    def underTest = new UnderTest(Mock(Proxy), new ProxySettingDTO(), connectionManager)

    expect: "method under test returns expected response"
    underTest.getConnectionResponseCode() == 200
  }
}

Try it in the Groovy web console.