1

I am trying to create a mock for Play's WSClient like this:

  def mockGet[A](url : String, method : String, headers : Seq[(String, String)], timeout : Duration)(
    response: Future[AhcWSResponse]
  ) =
    (mockWsClient
      .url(_ : String)
        .withMethod(_ : String)
        .withHttpHeaders(_: (String, String)*)
        .withRequestTimeout(_ : Duration)
        .stream())
      .expects(url, method, headers, timeout)
      .returning(response)

The problem is the withHttpHeaders - this actually takes (String, String)* but when I specify that type as above I get a compiler error like this:

[error]  found   : Seq[(String, String)]
[error]  required: (String, String)
[error]       .withHttpHeaders(_: Seq[(String, String)])

What type do I need to specify for this method because (String, String) is not correct. The actual real definition of this method is:

  override def withHttpHeaders(headers: (String, String)*): Self

UPDATE

I tried this after @Mario's suggestion:

  def mockGet[A](url: String, method: String, headers: Seq[(String, String)], timeout: Duration)(
    response: (String, String, Duration) => Future[ws.WSResponse]
  ) =
    (
      (
        xs: Seq[(String, String)]
      ) =>
        mockWsClient
          .url(_: String)
          .withMethod(_: String)
          .withRequestTimeout(_: Duration)
          .withHttpHeaders(xs: _*)
          .stream()
      )
      .expects(headers)
      .returning(response)

but this crashes the compiler with:

[error] value x$1

Mojo
  • 1,152
  • 1
  • 8
  • 16

1 Answers1

1

The key is to understand how the anonymous function placeholder parameter syntax works. For example, given

def f(i: Int*) = ???

then

f(_: Int)

expands to

(i: Int) => f(i)

Hence try

def mockGet(headers : Seq[(String, String)) =
  ((xs: Seq[(String, String)]) => mockWsClient.withHttpHeaders(xs: _*)).expects(headers)

Here is a simplified example

trait Zar {
  def f(i: Int*) = i
}

class ScalamockVarargsSpec extends FlatSpec with Matchers with MockFactory {
  "Varargs" should "be mockable" in {
    val zar = mock[Zar]
    ((xs: Seq[Int]) => zar.f(xs: _*)).expects(Seq(1,2))
    zar.f(1,2)
  }
}

In your particular case there are multiple anonymous function placeholder parameters, so try expanding them all, for example

def mockGet(url: String, headers : Seq[(String, String)) =
  ((u: String, xs: Seq[(String, String)]) => mockWsClient.url(u).withHttpHeaders(xs: _*))
    .expects(url, headers)
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • What's the purpose of headers param here? – Shankar Shastri Feb 20 '20 at 11:27
  • I tried you suggestion but modified it to account of all the parameters, but it resulted in a compiler crash. Please see my update to my post. Any idea why that is happening? I think we are nearly there – Mojo Feb 20 '20 at 15:11
  • Yes I did exactly that, but the code does not compile. Have you tried to compile it? – Mojo Feb 20 '20 at 15:56
  • Try to compile this: def mockGet(url: String, headers: Seq[(String, String)]) = ((u: String, xs: Seq[(String, String)]) => mockWsClient.url(u).withHttpHeaders(xs: _*)) .expects(url, headers) – Mojo Feb 20 '20 at 15:56
  • This results in: [error] Error while emitting FooSpec.scala [error] value u – Mojo Feb 20 '20 at 15:57