kitura-http-test

使 Kitura 框架中的处理程序测试变得超级简单的 Swift 包。

CircleCI

此示例实现了两个新的测试对象,它们受 Go 的 net/httptest 包的影响。
Sources/HTTPTest 包含两个类

这些包背后的意图是启用对处理程序的测试,而无需通过路由器运行。它提供了快速而简单的单元级别测试,允许轻松替换依赖项。

处理程序的结构以提供隔离

public class JSONHandlers {
  /**
  * If your handler needs dependencies then use constuctor
  * injection to manage this
  */
  public init(database:MySQL, logger:Log) {
    self.database = database
    self.logger = logger
  }
    /**
     * Handler for getting an application/json response.
     */
    public func getJSON(
      request: RouterRequest, 
      response: RouterResponse, 
      next: @escaping () -> Void) throws {

      // work for function

      }
}

可以通过使用构造函数注入在处理程序中隔离依赖项,通过依赖于使用协议的抽象,可以在测试阶段轻松地桩或模拟依赖项。

测试设置

Kitura 的 RouterRequest 和 RouterResponse 有一个基于协议 ServerRequest 和 ServerResponse 的底层对象,这些协议实现了 HTTP 请求和响应的基本数据结构。这些类本身没有其他依赖项,也不需要进一步的抽象来进行有效的测试。如果我们看一下下面的示例,我们正在创建 HTTPTest.Request 和 HTTPTest.ResponseRecorder 的实例,然后使用它来创建 RouterRequest 和 RouterResponse 的实例。Kitura 类确实对某些元素的构造函数具有保护级别,但这可以通过使用 @testable import KituraNet 声明在测试中绕过,这允许我们在测试中绕过它,而无需更改底层类中的保护。

public override func setUp() {
  request = Request(path:"/", method:"GET")
  routerRequest = RouterRequest(request: request!)

  response = ResponseRecorder()
  routerResponse = RouterResponse(
    response: response!,
    router: Router(),
    request: routerRequest!)

  handlers = JSONHandlers()
}

一旦我们完成了此设置,我们就可以编写像下面这样的单元测试,此测试使用 ResponseRecorder 上的便利方法,该方法捕获通常会发送到服务器输出的响应到内部缓冲区中。然后,我们可以将其作为原始对象或 JSON 访问,使我们能够断言来自处理程序的响应是所需的。

public func testReturnsJSONWhenValidRequest() throws {
  try handlers?.getJSON(request: routerRequest!, response: routerResponse!) {}
  let json = response!.jsonBody()

  XCTAssertEqual("Kitura", json["framework"], "Expected response body to contain Kitura")
}

这是一种非常有效的测试策略,因为这些测试不仅运行速度非常快,而且还允许对处理程序进行完整的代码路径检查。例如,如果身份验证失败,并且我们想确保服务器将返回 401 状态,则可以将负责身份验证的依赖项设置为返回失败状态,这将使我们能够测试处理程序是否通过正确的路径。

以这种方式分离代码的另一个好处是,通过将工作隔离到按行为分组的处理程序类中,我们可以保持路由器设置的简单性和可读性。

// JSON Get request
router.get("/json", handler: jsonHandlers.getJSON)