简体   繁体   中英

Play framework WSClient testing

I have a service class in my code, for example, UserService. It has a WSClient member which makes calls to a web service. I would like to write test cases for the UserService methods.

I did some research on testing WSClient but did not find any use case like mine. Should I establish a live test service, or do mocking? This is another question.

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


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

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

These methods use the WSClient to call the web service endpoints.

I would like to write test cases for these methods. Which is the best, setting up a test service and call that or mocking the WSClient?

I have created a CustomWSClient, CustomWSRequest and CustomWSResponse for testing purposes as follows.

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)

I have created a mock where ever ws object is used.

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM