Test WebSocket in PlayFramework

前端 未结 4 1802
梦如初夏
梦如初夏 2021-02-20 16:32

I have a WebSocket in my Play application and I want to write a test for it, but I couldn\'t find any example on how to write such a test. I found a discussion in the play-frame

相关标签:
4条回答
  • 2021-02-20 16:48

    Chrome provides a plugin to test websocket service.

    Edit

    So using the plugin (as shown in picture below) you can provide websocket url and the request data and send message to service. And message log shows the message sent from client and also service response.

    enter image description here

    0 讨论(0)
  • 2021-02-20 16:57

    You can retrieve underlying Iteratee,Enumerator and test them directly. This way you don't need to use a browser. You need akka-testkit though, to cope with asynchronous nature of iteratees.

    A Scala example:

    object WebSocket extends Controller {
      def websocket = WebSocket.async[JsValue] { request =>
        Future.successful(Iteratee.ignore[JsValue] -> Enumerator.apply[JsValue](Json.obj("type" -> "error")))   
      }
    }
    
    class WebSocketSpec extends PlaySpecification {    
      "WebSocket" should {
        "respond with error packet" in new WithApplication {
          val request = FakeRequest()
    
          var message: JsValue = null
          val iteratee = Iteratee.foreach[JsValue](chunk => message = chunk)(Akka.system.dispatcher)
    
          Controller.websocket().f(request)(Enumerator.empty[JsValue],iteratee)
    
          TestKit.awaitCond(message == Json.obj("type" -> "error"), 1 second)
        }
      }
    }
    
    0 讨论(0)
  • 2021-02-20 16:59

    Assume that you have a websocket library that returns the Future[Itearatee[JsValue, Unit], Enumerator[JsValue]] your controller uses

    trait WSLib {
      def connect: Future[Itearatee[JsValue, Unit], Enumerator[JsValue]]
    }
    

    And you wanna test this library.

    Here is a context you can use:

    trait WebSocketContext extends WithApplication {
      val aSecond = FiniteDuration(1, TimeUnit.SECONDS)
    
    
      case class Incoming(iteratee: Iteratee[JsValue, Unit]) {
    
        def feed(message: JsValue) = {
          iteratee.feed(Input.El(message))
        }
    
        def end(wait: Long = 100) = {
          Thread.sleep(wait) //wait until all previous fed messages are handled
          iteratee.feed(Input.EOF)
        }
      }
    
      case class OutGoing(enum: Enumerator[JsValue]) {
        val messages = enum(Iteratee.fold(List[JsValue]()) {
          (l, jsValue) => jsValue :: l
        }).flatMap(_.run)
    
        def get: List[JsValue] = {
          Await.result(messages, aSecond)
        }
      }
    
      def wrapConnection(connection: => Future[Iteratee[JsValue, Unit], Enumerator[JsValue]]): (Incoming, OutGoing) = {
        val (iteratee, enumerator) = Await.result(conn, aSecond)
        (Incoming(iteratee), OutGoing(enumerator))
      }
    
    }
    

    Then your tests can be written as

    "return all subscribers when asked for info" in new WebSocketContext  {
      val (incoming, outgoing) = wrapConnection(myWSLib.connect)
    
      incoming.feed(JsObject("message" => "hello"))
      incoming.end() //this closes the connection
    
    
      val responseMessages = outgoing.get  //you only call this "get" after the connection is closed
      responseMessages.size must equalTo(1)
      responseMessages must contain(JsObject("reply" => "Hey"))
    }
    

    Incoming represent the messages coming from the client side, while the outgoing represents the messages sent from the server. To write test, you first feed in the incoming messages from incoming and then close the connection by calling incoming.end, then you get the complete list of outgoing messages from the outgoing.get method.

    0 讨论(0)
  • 2021-02-20 17:04

    I test WebSockets code using Firefox:

    https://github.com/schleichardt/stackoverflow-answers/commit/13d5876791ef409e092e4a097f54247d851e17dc#L8R14

    For Java it works similar replacing 'HTMLUNIT' with 'FIREFOX': http://www.playframework.com/documentation/2.1.x/JavaFunctionalTest

    0 讨论(0)
提交回复
热议问题