Scala 单元测试Rest API客户端的方法有哪些?例如,测试是否发送了正确的Rest请求

Scala 单元测试Rest API客户端的方法有哪些?例如,测试是否发送了正确的Rest请求,scala,scalatest,akka-http,Scala,Scalatest,Akka Http,在工作中,我们正在开发一个介于其他两个服务之间的服务。我们公开了一个Rest API,该API由某个服务调用——请求由某个逻辑处理,然后根据该逻辑,HTTP请求将被发送到另一个服务 互联网上有很多关于如何最好地测试您提供的API端点的资源。一、 另一方面,我们希望测试发送了哪些API请求,而不将它们发送到实际的服务 我想我可以在localhost:8080上设置一个完整的服务器框架,只记录它接收到的内容,但这感觉有点脏。测试我们为外部服务提供的RESTAPI时,我们使用akka http进行测试

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

互联网上有很多关于如何最好地测试您提供的API端点的资源。一、 另一方面,我们希望测试发送了哪些API请求,而不将它们发送到实际的服务

我想我可以在localhost:8080上设置一个完整的服务器框架,只记录它接收到的内容,但这感觉有点脏。测试我们为外部服务提供的RESTAPI时,我们使用akka http进行测试,使用akka http testkit进行测试非常舒服,这是非常好的。我只是想知道是否有比较适合使用工具来测试Http请求发出的内容。

我们以您称之为脏的方式进行测试,尽管我认为这并不脏

我们有一个基本特性,即启动/关闭使用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]

}
然后我们将其混合到我们的客户规范中

类似这样的东西

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

}
在您的规范中,您使用客户端调用模拟服务器 使用s$rootURI/success或s$rootURI/failure端点并检查它是否正确处理响应。 另外,lastRequest变量总是有最后一个请求问题,所以您可以针对它运行断言,如

lastRequest.headers should contain(`Accept-Encoding`(ContentCoding.gzip))
这种方法对我们来说非常有效,我们可以测试我们的客户机是否能够处理来自服务器的各种输出以及他们执行的所有请求操作功能编程工具

我发现测试这些场景的最简单方法是在设计中使用简单的旧函数编程原则。您可以将路由创建嵌入到高阶函数中。此高阶函数将接收查询下游服务的函数:

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
}