面临问题测试 akka http 缓存

Facing issue testing akka http cache

我正在使用 Akka HTTP 缓存来缓存我的结果。但是我在测试它时遇到了问题。

class GoogleAnalyticsController @Inject()(cache: Cache[String, HttpResponse],
                                          googleAnalyticsApi: GoogleAnalyticsTrait,
                                          googleAnalyticsHelper: GoogleAnalyticsHelper)
                                         (implicit system: ActorSystem, materializer: ActorMaterializer) {


def routes: Route =

      post {
        pathPrefix("pageviews") {
          path("clients" / Segment) { accountsClientId =>
            entity(as[GoogleAnalyticsMetricsRequest]) { googleAnalyticsMetricsRequest =>
         val googleAnalyticsMetricsKey = "key"
         complete(
           cache.getOrLoad(googleAnalyticsMetricsKey, _ => getGoogleAnalyticsMetricsData(accountsClientId, googleAnalyticsMetricsRequest))
          ) 
         }

       }
     }
   }

 private def getGoogleAnalyticsMetricsData(accountsClientId: String,
                                            request: GoogleAnalyticsMetricsRequest) = {
    val payload = generate(request)
    val response = googleAnalyticsApi.googleAnalyticsMetricResponseHandler(accountsClientId, payload) // response from another microservice
googleAnalyticsHelper.googleAnalyticsMetricResponseHandler(
       googleAnalyticsMetricsRequest.metricName, response)
}

}

class GoogleAnalyticsHelper extends LoggingHelper {

  def googleAnalyticsMetricResponseHandler(metricName: String, response: Either[Throwable, Long]): Future[HttpResponse] =
    response.fold({ error =>
      logger.error(s"An exception has occurred while getting $metricName from behavior service and error is ${error.getMessage}")
      Marshal(FailureResponse(error.getMessage)).to[HttpResponse].map(httpResponse => httpResponse.copy(status = StatusCodes.InternalServerError))
    }, value =>
      Marshal(MetricResponse(metricName, value)).to[HttpResponse].map(httpResponse => httpResponse.copy(status = StatusCodes.OK))
    )

}

测试用例:只分享相关部分

"get success metric response for " + pageviews + " metric of given accounts client id" in { fixture =>
      import fixture._

      val metricResponse = MetricResponse(pageviews, 1)
      val eventualHttpResponse = Marshal(metricResponse).to[HttpResponse].map(httpResponse => httpResponse.copy(status = StatusCodes.OK))

      when(cache.getOrLoad(anyString, any[String => Future[HttpResponse]].apply)).thenReturn(eventualHttpResponse)
      when(googleAnalyticsApi.getDataFromGoogleAnalytics(accountsClientId, generate(GoogleAnalyticsRequest(startDate, endDate, pageviews))))
        .thenReturn(ApiResult[Long](Some("1"), None))
      when(googleAnalyticsHelper.googleAnalyticsMetricResponseHandler(pageviews, Right(1))).thenReturn(eventualHttpResponse)

      Post(s"/pageviews/clients/$accountsClientId").withEntity(requestEntity) ~>
        googleAnalyticsController.routes ~> check {
        status shouldEqual StatusCodes.OK
        responseAs[String] shouldEqual generate(metricResponse)
      }
    }

通过这样做,我最好测试缓存是否有密钥但不能测试缓存是否未命中。在代码覆盖率中,它遗漏了以下突出显示的部分

cache.getOrLoad(googleAnalyticsMetricsKey, _ => getGoogleAnalyticsMetricsData(accountsClientId, googleAnalyticsMetricsRequest))

如果存在设计问题,请随时指导我如何使我的设计可测试。

提前致谢。

我认为您不需要模拟缓存。您应该为缓存创建一个实际对象而不是模拟对象。

你所做的是,你已经模拟了缓存,在这种情况下,突出显示的部分将不会被调用,因为你正在提供模拟值。在以下存根中,只要找到 cache.getOrLoad,就会返回 eventualHttpResponse

when(cache.getOrLoad(anyString, any[String => Future[HttpResponse]].apply)).thenReturn(eventualHttpResponse)

因此函数 getGoogleAnalyticsMetricsData(accountsClientId, googleAnalyticsMetricsRequest) 永远不会被调用。