单元测试Rest API客户端的方法有哪些-即测试是否发送了正确的Rest请求

时间:2018-07-03 22:20:40

标签: scala scalatest akka-http

在工作中,我们正在开发位于其他两个服务之间的服务。我们公开了一个由某些服务调用的Rest API-请求由某种逻辑处理,然后根据该逻辑,HTTP请求将被发送到另一个服务。

Internet上有很多资源,可以最好地测试您提供的API端点。另一方面,我想测试发送哪些API请求,而不将其发送到实际服务。

我想我总是可以在localhost:8080上设置整个服务器框架,只记录接收到的内容,但这有点脏。测试我们为外部服务提供的Rest API(我们使用akka-http来做到这一点)非常适合使用akka-http-testkit进行测试。我只是想知道是否可以使用工具来测试Http请求的需求。

2 个答案:

答案 0 :(得分:1)

功能性编程“工具”

我发现测试这些方案的最简单方法是在设计中使用普通的函数式编程原理。您可以将Route创建的内容嵌入到更高阶的函数中。此更高阶的函数将采用查询下游服务的函数:

type ComputedData = ???

val computeData : HttpRequest => ComputedData = ???

def intermediateRoute(downstreamService : ComputedData => Future[HttpResponse]) : Route = 
  extractRequest { request =>
    val computedData : ComputedData = computeData(request)

    complete(downstreamService(computedData))
  }

此高阶函数现在可以在生产环境中使用:

val queryDownStreamService : ComputedData => Future[HttpResponse] = ???

val productionRoute : Route = intermediateRoute(queryDownStreamService)

或者,它可以用于单元测试以确保逻辑正确:

val testComputedData : ComputedData => Boolean = ???

val testResponse : HttpResponse = ???

val testService : ComputedData => Future[HttpResponse] = (computedData) => {
  assert(testComputedData(computedData))

  Success(testResponse)
}

val testRoute = intermediateRoute(testService)

Get("/test") ~> testRoute ~> check {
  response should be testResponse
}

答案 1 :(得分:0)

我们以您称为dirty的方式进行操作,尽管我不认为它是dirty

我们具有启动/关闭服务器的基本特征(我们使用http4s和scalatest)

trait EmbeddedServer extends BeforeAndAfterAll with Http4sDsl[IO] {
  self: Suite =>

  private var server: Server[IO] = _

  protected var lastRequest: Request[IO] = _

  private def captureRequest: HttpService[IO] = Kleisli { req: Request[IO] =>
    lastRequest = req
    service(req)
  }

  override protected def beforeAll(): Unit = {
    server = BlazeBuilder[IO]
      .bindAny()
      .mountService(captureRequest, "/")
      .start
      .unsafeRunSync()
    super.beforeAll()
  }

  override protected def afterAll(): Unit = {
    super.afterAll()
    server.shutdownNow()
  }

  def address: InetSocketAddress = server.address

  def rootURI: String = s"http:/$address"

  def service: HttpService[IO]

}

然后我们将其混合到client规范中

遵循这些原则

class SomeRequesterSpec extends WordSpec with EmbeddedServer {

  override def service: HttpService[IO] = HttpService[IO] {
    case GET -> Root / "failure" => ServiceUnavailable()
    case GET -> Root / "success" => Ok(SuccessBody)
    case GET -> Root / "partial-success" => Ok(PartialSuccessBody)
    case GET -> Root / "malformed" => Ok(MalformedBody)
    case GET -> Root / "empty" => Ok(EmptyResponse)
  }

  //... you specs go here

}

根据您的要求,您可以与客户呼叫mocked服务器 使用s"$rootURI/success"s"$rootURI/failure"端点并检查其是否正确处理了响应。 此外,lastRequest var总是有最后一个请求问题,因此您可以针对它运行断言,例如

lastRequest.headers should contain(`Accept-Encoding`(ContentCoding.gzip))

这种方法对我们来说非常有效,我们可以测试我们的客户是否处理了服务器的各种输出以及他们要求的所有操作