0

我的代码中有一个服务类,例如 UserService。它有一个调用 Web 服务的 WSClient 成员。我想为 UserService 方法编写测试用例。

我对测试 WSClient 进行了一些研究,但没有找到像我这样的用例。我应该建立一个现场测试服务,还是做模拟?这是另一个问题。

class UserService @Inject()(ws: WSClient) {


def getUser(userId: UUID) = {// some code}

def createUser(obj: User) = {// another piece of code}

这些方法使用 WSClient 调用 Web 服务端点。

我想为这些方法编写测试用例。哪个是最好的,设置一个测试服务并调用它或模拟 WSClient?

4

1 回答 1

0

我创建了一个 CustomWSClient、CustomWSRequest 和 CustomWSResponse 用于测试目的,如下所示。

package unittest

import play.api.http.Writeable
import play.api.libs.iteratee.Enumerator
import play.api.libs.json.{JsValue, Json}
import play.api.libs.ws._

import scala.concurrent.Future
import scala.xml.Elem

class CustomWSClient extends WSClient {

  var t: ResponseObject = new ResponseObject(Json.toJson("Success"), Map("trial" -> Seq("value")), 200)

  override def underlying[T]: T = underlying.asInstanceOf[T]

  override def url(url: String): WSRequest = {
    var c: CustomWSRequest = CustomWSRequest(url, t)
    c.setResponse(t)
    c
  }

  override def close(): Unit = {}
  def setResponse(t: ResponseObject) = {
    this.t = t
  }

}

case class CustomWSRequest(inputUrl: String, t: ResponseObject) extends WSRequest {
  override val url: String = inputUrl

  override def withHeaders(hdrs: (String, String)*): WSRequest = { this }

  override def withAuth(username: String, password: String, scheme: WSAuthScheme): WSRequest = { this }

  override def withQueryString(parameters: (String, String)*): WSRequest = { this }

  override def execute(): Future[WSResponse] = { Future.successful(CustomWSResponse(t)) }

  override def sign(calc: WSSignatureCalculator): WSRequest = { this }

  override def stream(): Future[(WSResponseHeaders, Enumerator[Array[Byte]])] = null

  override def withVirtualHost(vh: String): WSRequest = { this }

  override def withMethod(method: String): WSRequest = { this }

  override def withRequestTimeout(timeout: Long): WSRequest = { this }

  override def withProxyServer(proxyServer: WSProxyServer): WSRequest = { this }

  override def withFollowRedirects(follow: Boolean): WSRequest = { this }

  override def withBody(body: WSBody): WSRequest = { this }

  override def get(): Future[WSResponse] = { Future.successful(CustomWSResponse(t)) }

  override def post[T](body: T)(implicit wrt: Writeable[T]) = { Future.successful(CustomWSResponse(t)) }

  //override def put[T](body: T)(implicit wrt: Writeable[T]) = {Future.successful( CustomWSResponse(t))}

  def setResponse(t: ResponseObject) = {
    t
  }


  override val calc: Option[WSSignatureCalculator] = None
  override val queryString: Map[String, Seq[String]] = Map("trial" -> Seq("value"))
  override val method: String = "TestMethod"
  override val followRedirects: Option[Boolean] = None
  override val body: WSBody = null
  override val requestTimeout: Option[Int] = None
  override val virtualHost: Option[String] = None
  override val proxyServer: Option[WSProxyServer] = None
  override val auth: Option[(String, String, WSAuthScheme)] = None
  override val headers: Map[String, Seq[String]] = Map("trial" -> Seq("value"))

}

case class CustomWSResponse(t: ResponseObject) extends play.api.libs.ws.WSResponse {
  def allHeaders: Map[String, Seq[String]] = { t.headers }

  def statusText: String = { "success" }

  def underlying[T]: T = underlying.asInstanceOf[T]

  def body: String = { t.json.toString() }

  def header(key: String): Option[String] = Option(t.headers.get(key).headOption.get.apply(0))

  def cookie(name: String): Option[WSCookie] = Some(CustomWSCookie("test"))

  def status: Int = { t.status }
  def json: JsValue = t.json

  override def cookies: Seq[WSCookie] = Seq(CustomWSCookie("test"))

  override def xml: Elem = null

  override def bodyAsBytes: Array[Byte] = null
}

case class CustomWSCookie(t: String) extends play.api.libs.ws.WSCookie {

  override def underlying[T]: T = this.underlying

  override def domain: String = "test"

  override def name: Option[String] = Some("test")

  override def value: Option[String] = Some("test")

  override def path: String = "test"

  override def expires: Option[Long] = Some(2L)

  override def maxAge: Option[Int] = Some(5)

  override def secure: Boolean = true
}

case class ResponseObject(json: JsValue, headers: Map[String, Seq[String]], status: Int)

我创建了一个使用 ws 对象的模拟。

class TranslationsActorSpec extends ServiceOneAppPerSuite with LazyLogging {

  override val ws = mock[CustomWSClient]
  val mockWSRequest = mock[CustomWSRequest]
  val mockWSResponse = mock[CustomWSResponse]

  when(ws.url("https://getCallToMyService")) thenReturn (mockWSRequest)
  when(mockWSRequest.withHeaders(
    "Authorization" -> "token somevalue"
  )) thenReturn (mockWSRequest)
  when(mockWSRequest.get()) thenReturn (Future.successful(mockWSResponse))
  when(mockWSResponse.status) thenReturn (200)
  //write your testcase and pass ws object to it, it will get the mocked response for the service call
}
于 2019-08-05T13:47:18.337 回答