【问题标题】:how to mock external WS API calls in Scala Play framework如何在 Scala Play 框架中模拟外部 WS API 调用
【发布时间】:2017-07-11 03:54:06
【问题描述】:

我有一个现有的 Scala 播放应用程序,它有一个调用另一个外部 REST API 的 REST API。我想模拟为内部测试返回虚假 JSON 数据的外部 Web 服务。基于以下示例:https://www.playframework.com/documentation/2.6.x/ScalaTestingWebServiceClients

我完全按照文档中的示例进行操作,但由于类 Action 已弃用而出现编译器错误。

import play.core.server.Server
import play.api.routing.sird._
import play.api.mvc._
import play.api.libs.json._
import play.api.test._

import scala.concurrent.Await
import scala.concurrent.duration._

import org.specs2.mutable.Specification
import product.services.market.common.GitHubClient

class GitHubClientSpec extends Specification {
  import scala.concurrent.ExecutionContext.Implicits.global

  "GitHubClient" should {
    "get all repositories" in {

      Server.withRouter() {
        case GET(p"/repositories") => Action {
          Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
        }
      } { implicit port =>
        WsTestClient.withClient { client =>
          val result = Await.result(
            new GitHubClient(client, "").repositories(), 10.seconds)
          result must_== Seq("octocat/Hello-World")
        }
      }
    }
  }
}

mvc 包中的对象 Action 已弃用:注入 ActionBuilder (例如 DefaultActionBuilder)或扩展 BaseController/AbstractController/InjectedController

这是最新官方文档中的主要示例,实际上包含编译时错误,鉴于此示例不起作用,如何使用 Scala Play 轻松模拟外部 API 的正确方法是什么?

【问题讨论】:

    标签: scala rest unit-testing playframework mocking


    【解决方案1】:

    您可以将示例更改为:

    Server.withRouterFromComponents() { cs => {
        case GET(p"/repositories") => cs.defaultActionBuilder {
          Results.Ok(Json.arr(Json.obj("full_name" -> "octocat/Hello-World")))
        }
      }
    } { implicit port =>
      WsTestClient.withClient { client =>
        val result = Await.result(
          new GitHubClient(client, "").repositories(), 10.seconds)
        result should be(Seq("octocat/Hello-World"))
      }
    }
    

    说实话,我不能 100% 确定这是否是最好的方法。不过,我已经向游戏框架提交了PR,因此您可能会看到来自制造商的 cmets 空间。

    【讨论】:

      【解决方案2】:

      如果您使用的是独立版本的 play-ws,您可以像这样使用这个库 https://github.com/f100ded/play-fake-ws-standalone

      import akka.actor.ActorSystem
      import akka.stream.ActorMaterializer
      import org.f100ded.play.fakews._
      import org.scalatest._
      import play.api.libs.ws.JsonBodyWritables._
      
      import scala.concurrent.duration.Duration
      import scala.concurrent._
      import scala.language.reflectiveCalls
      
      /**
        * Tests MyApi HTTP client implementation
        */
      class MyApiClientSpec extends AsyncFlatSpec with BeforeAndAfterAll with Matchers {
      
        implicit val system = ActorSystem()
        implicit val materializer = ActorMaterializer()
        import system.dispatcher
      
        behavior of "MyApiClient"
      
        it should "put access token to Authorization header" in {
          val accessToken = "fake_access_token"
          val ws = StandaloneFakeWSClient {
            case request @ GET(url"http://host/v1/foo/$id") =>
              // this is here just to demonstrate how you can use URL extractor
              id shouldBe "1"
      
              // verify access token
              request.headers should contain ("Authorization" -> Seq(s"Bearer $accessToken"))
      
              Ok(FakeAnswers.foo)
          }
      
          val api = new MyApiClient(ws, baseUrl = "http://host/", accessToken = accessToken)
          api.getFoo(1).map(_ => succeed)
        }
      
        // ... more tests
      
        override def afterAll(): Unit = {
          Await.result(system.terminate(), Duration.Inf)
        }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2015-01-20
        • 1970-01-01
        • 2013-04-03
        • 1970-01-01
        • 2015-04-17
        • 1970-01-01
        • 1970-01-01
        • 2022-06-30
        • 1970-01-01
        相关资源
        最近更新 更多