Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the client mockable with Java mocking frameworks #108

Closed
akkie opened this issue May 5, 2017 · 13 comments
Closed

Make the client mockable with Java mocking frameworks #108

akkie opened this issue May 5, 2017 · 13 comments

Comments

@akkie
Copy link

akkie commented May 5, 2017

Play WS Version (2.5.x / etc)

1.0.0-M8

API (Scala / Java / Neither / Both)

Scala

Expected Behavior

It should be able to mock the client with Java mocking libraries like mockito, EasyMock or JMock.

Actual Behavior

The following code doesn't compile:

val wsRequest = mock[WSRequest]
val wsResponse = mock[WSResponse]

wsResponse.json throws new RuntimeException("Unexpected character ('<' (code 60))")
wsResponse.body returns "<html></html>"
wsRequest.withHeaders(any) returns wsRequest
wsRequest.post[Map[String, Seq[String]]](any)(any) returns Future.successful(wsResponse)
/home/travis/build/mohiva/play-silhouette/silhouette/test/com/mohiva/play/silhouette/impl/providers/OAuth2ProviderSpec.scala:274: type mismatch;
[error]  found   : this.wsRequest.type (with underlying type play.api.libs.ws.WSRequest)
[error]  required: this.wsRequest.Self
[error]       wsRequest.withHeaders(any) returns wsRequest

/home/travis/build/mohiva/play-silhouette/silhouette/test/com/mohiva/play/silhouette/impl/providers/OAuth2ProviderSpec.scala:275: type mismatch;
[error]  found   : this.wsResponse.type (with underlying type play.api.libs.ws.WSResponse)
[error]  required: this.wsRequest.Response
[error]       wsRequest.post[Map[String, Seq[String]]](any)(any) returns Future.successful(wsResponse)

Reproducible Test Case

mohiva/play-silhouette#509

Links

https://groups.google.com/forum/#!topic/play-framework/mYPRPbfa8Uk

Notes

Both Scala testing libraries support mocking with Java mocking frameworks. ScalaTest supports one Scala and three Java mocking frameworks. Specs2 provides syntactic sugar for mockito. This shows that using Java mocking frameworks in the Scala world is a preferred method.

Switching to play-mockws as suggested by @wsargent , isn't a good solution for a play related library, because then the library is bound to the release cycle of that play related dependency.

@wsargent
Copy link
Member

wsargent commented May 8, 2017

The other option is to add a mock implementation directly if possible.

@akkie
Copy link
Author

akkie commented May 9, 2017

@wsargent Could you please illustrate this a bit more? Do you mean based on the play-ws traits without the typing stuff (which I think isn't possible) or a complete implementation like play-mockws? Or do you mean a wrapper around the play-ws functionality`? But then I have to test this wrapper too, which isn't easily possible.

@wsargent
Copy link
Member

wsargent commented May 9, 2017

Basically -- taking play-mockws and merging it into play-ws. Then the release cycle problem goes away.

@akkie
Copy link
Author

akkie commented May 9, 2017

This would be an option. But is it worth to implement a mock implementation instead of using types based on generics? I don't know the problems you had with the generic implementation. Does it generally not work or is it only ugly?

@akkie
Copy link
Author

akkie commented May 23, 2017

@wsargent I need to know if there is a solution for the final Play 2.6 release, so that I can proceed with my tasks. A short info would be great!

@wsargent
Copy link
Member

Hi @akkie can you provide a small self-contained project as described in https://groups.google.com/d/msg/play-framework/mYPRPbfa8Uk/DFl3ONJcAgAJ ?

@wsargent
Copy link
Member

wsargent commented May 23, 2017

@akkie This unit test seems to work fine:

package play.api.libs.ws

import org.specs2.mock.Mockito
import org.specs2.mutable.Specification

import scala.concurrent.Future

class MockitoSpec extends Specification with Mockito {

  trait WSRequest extends StandaloneWSRequest {
    type Self = StandaloneWSRequest
    type Response = StandaloneWSResponse
  }

  "wsrequest" should {

    "be mockable" in {
      val wsRequest = mock[WSRequest]
      val wsResponse = mock[StandaloneWSResponse]

      wsResponse.json throws new RuntimeException("Unexpected character ('<' (code 60))")
      wsResponse.body returns "<html></html>"
      wsRequest.withHeaders(any) returns wsRequest
      wsRequest.post[Map[String, Seq[String]]](any)(any) returns Future.successful(wsResponse)

      success
    }
  }
}
[info] 
[info] MockitoSpec
[info] 
[info] wsrequest should
[info]   + be mockable
[info] 
[info] 

@akkie
Copy link
Author

akkie commented May 24, 2017

@wsargent Yes it works, but normally you deal with the WSClient and not only with the request and the response parts. So it's possible to define your own request trait, but with the currently provided methods, you cannot assign this custom class to your WSClient.url method, which is mostly the entry point in your implementations.

But, you brought me to an idea. From the beginning, I've used the HTTPLayer trait to provide a mockable implementation for the previously provided global WSClient object. And this allows my to create a MockHTTPLayer which uses a custom MockWSRequest. This works now as expected!

@wsargent
Copy link
Member

Awesome!

@wsargent wsargent closed this as completed Jun 8, 2017
@raphaelbauer
Copy link

Just as a quick feedback. We converted our projects to Play 2.6 and the latest wsClient (lots and lots of code, lots and lots of mocks of wsClient stuff).

And all worked perfectly fine.

👍

@marcospereira
Copy link
Member

Thanks for the feedback, @raphaelbauer!

@jhz7
Copy link

jhz7 commented Jul 11, 2018

Any one knows how to solve the "Unexpected character ('<' (code 60))" on wsResponse.json?

@marcospereira
Copy link
Member

Hi @jhz7,

Our forums would be a better place to discuss this. It would be good if you can share some code there too, and the JSON Play WS is getting. Is it valid? What JSONLint says about it?

Best.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants