在工作中,我们正在开发位于其他两个服务之间的服务。我们公开了一个由某些服务调用的Rest API-请求由某种逻辑处理,然后根据该逻辑,HTTP请求将被发送到另一个服务。
Internet上有很多资源,可以最好地测试您提供的API端点。另一方面,我想测试发送哪些API请求,而不将其发送到实际服务。
我想我总是可以在localhost:8080上设置整个服务器框架,只记录接收到的内容,但这有点脏。测试我们为外部服务提供的Rest API(我们使用akka-http来做到这一点)非常适合使用akka-http-testkit进行测试。我只是想知道是否可以使用工具来测试Http请求的需求。
答案 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))
这种方法对我们来说非常有效,我们可以测试我们的客户是否处理了服务器的各种输出以及他们要求的所有操作