Akka Http:如何使用流向第三方服务的流测试路由?
我在akka http应用程序中有一个路由,它通过Akka Http:如何使用流向第三方服务的流测试路由?,akka,akka-http,akka-stream,akka-testkit,Akka,Akka Http,Akka Stream,Akka Testkit,我在akka http应用程序中有一个路由,它通过http().cachedHostConnectionPoolHttps与第三方服务集成。我想用正确的方法来测试它。但不确定应该如何:( 以下是此路线的外观: val routes: Route = pathPrefix("access-tokens") { pathPrefix(Segment) { userId => parameters('refreshToken) { refreshToken => o
http().cachedHostConnectionPoolHttps
与第三方服务集成。我想用正确的方法来测试它。但不确定应该如何:(
以下是此路线的外观:
val routes: Route = pathPrefix("access-tokens") {
pathPrefix(Segment) { userId =>
parameters('refreshToken) { refreshToken =>
onSuccess(accessTokenActor ? GetAccessToken(userId, refreshToken)) {
case token: AccessToken => complete(ok(token.toJson))
case AccessTokenError => complete(internalServerError("There was problems while retriving the access token"))
}
}
}
}
此路由后面隐藏了所有逻辑发生的accessTokenActor
,如下所示:
class AccessTokenActor extends Actor with ActorLogging with APIConfig {
implicit val actorSystem = context.system
import context.dispatcher
implicit val materializer = ActorMaterializer()
import AccessTokenActor._
val connectionFlow = Http().cachedHostConnectionPoolHttps[String]("www.service.token.provider.com")
override def receive: Receive = {
case get: GetAccessToken => {
val senderActor = sender()
Source.fromFuture(Future.successful(
HttpRequest(
HttpMethods.GET,
"/oauth2/token",
Nil,
FormData(Map(
"clientId" -> youtubeClientId,"clientSecret" -> youtubeSecret,"refreshToken" -> get.refreshToken))
.toEntity(HttpCharsets.`UTF-8`)) -> get.channelId
)
)
.via(connectionFlow)
.map {
case (Success(resp), id) => resp.status match {
case StatusCodes.OK => Unmarshal(resp.entity).to[AccessTokenModel]
.map(senderActor ! AccessToken(_.access_token))
case _ => senderActor ! AccessTokenError
}
case _ => senderActor ! AccessTokenError
}
}.runWith(Sink.head)
case _ => log.info("Unknown message")
}
}
因此,问题是如何更好地测试这条路线,要记住,拥有流的演员也存在于它的引擎盖下。构图 测试当前组织的路由逻辑的一个困难是很难隔离功能。如果没有
参与者
,则无法测试路由
逻辑,如果没有路由,则很难测试参与者查询
我认为函数组合可以更好地为您服务,这样您就可以隔离您要测试的内容
首先抽象出参与者
查询(ask):
现在,将您的routes
值转换为更高阶的方法,该方法将查询函数作为参数:
val actorRef : ActorRef = ??? //not shown in question
type TokenQuery = GetAccessToken => Future[TokenResponse]
val actorTokenQuery : TokenQuery = queryActorForToken(actorRef)
val errorMsg = "There was problems while retriving the access token"
def createRoute(getToken : TokenQuery = actorTokenQuery) : Route =
pathPrefix("access-tokens") {
pathPrefix(Segment) { userId =>
parameters('refreshToken) { refreshToken =>
onSuccess(getToken(GetAccessToken(userId, refreshToken))) {
case token: AccessToken => complete(ok(token.toJson))
case AccessTokenError => complete(internalServerError(errorMsg))
}
}
}
}
//original routes
val routes = createRoute()
测试
现在您可以测试queryActorForToken
而不需要Route
,也可以测试createRoute
方法而不需要参与者
您可以使用始终返回预定义令牌的注入函数测试createRoute:
val testToken : AccessToken = ???
val alwaysSuccceedsRoute = createRoute(_ => Success(testToken))
Get("/access-tokens/fooUser?refreshToken=bar" ~> alwaysSucceedsRoute ~> check {
status shouldEqual StatusCodes.Ok
responseAs[String] shouldEqual testToken.toJson
}
或者,您可以使用从不返回令牌的注入函数测试createRoute:
val alwaysFailsRoute = createRoute(_ => Success(AccessTokenError))
Get("/access-tokens/fooUser?refreshToken=bar" ~> alwaysFailsRoute ~> check {
status shouldEqual StatusCodes.InternalServerError
responseAs[String] shouldEqual errorMsg
}
在您的测试中实例化一个模拟web http服务器并接收调用?@DiegoMartinoia是的,这是最明显的情况。如果在这种情况下没有其他方法可以工作,我会这样做。实际上,我正在寻找一些针对akka流的测试技术。类似于使用fake的流替换…您对此有何看法?在喷射和模拟是,如果“真正的”依赖关系被打破,你的测试不会失败。我在这方面是少数,但特别是当涉及到一些复杂的事情,如远程http调用时,我喜欢黑盒子的东西。特别是Akka应用程序通常有很多你想测试的“奇怪”东西(持久性、切分、集群)实际上,我发现更容易旋转应用程序并在最后对其进行探测。但这是一种微不足道的方法:)直到一天结束,我明白我的错误是把所有东西都放在一起。我需要有更多的独立组件!
val alwaysFailsRoute = createRoute(_ => Success(AccessTokenError))
Get("/access-tokens/fooUser?refreshToken=bar" ~> alwaysFailsRoute ~> check {
status shouldEqual StatusCodes.InternalServerError
responseAs[String] shouldEqual errorMsg
}