使用Jasmine在JavaScript中存储WebSocket

时间:2014-04-18 10:12:24

标签: javascript testing websocket jasmine stub

我尝试测试onmessage是否是正确的功能。

这是一个测试:

  describe(".init(address, window)", function() {
    beforeEach(function() {
      address = 'ws://test.address';
      window = {};
      e = {
        data: {}
      }
      spyOn(window, 'WebSocket').and.returnValue(function() {return {onmessage: null}});
      spyOn(subject, 'handleMessage');
    });

    it("should create a WebSocket client which connects to the given address", function() {
      subject.init(address, window);
      expect(window.WebSocket).toHaveBeenCalledWith(address);
    });

    it("should have onmessage method overriden with a function which handles message", function() {
      ws = subject.init(address, window);
      alert(JSON.stringify(ws));
      ws.onmessage(e);
      expect(subject.handleMessage).toHaveBeenCalledWith(e.data);
    });
  });

以下是实施:

FL.init = function(address, window) {
  if ('WebSocket' in window) {
    var ws = new WebSocket(address);
    ws.onmessage = function(e) {
      this.handleMessage(e.data);
    };
    return ws;
  }
};

第一次测试通过。在第二个中,wsundefined。这是为什么?我试过一个控制台new function() {return {onmessage: null}},它看起来应该没问题。

2 个答案:

答案 0 :(得分:11)

我并不完全确定我是否知道您的代码应该如何表现,但是如果您需要监视WebSocket构造函数和stub .send方法来模拟一些传入的消息,这是如何实现它。

要监视WebSocket,您需要致电.and.callThrough而不是returnValue。然而,由于抱怨缺少new关键字(如here中所述),因此您需要伪造构造函数:

var realWS = WebSocket;
var WebSocketSpy = spyOn(window, "WebSocket").and.callFake(function(url,protocols){
  return new realWS(url,protocols);
});

要为传入的消息制作间谍,您可以这样做

var onmessageCallbackSpy = jasmine.createSpy('onmessageCallback');

你也可以监视.send方法,并提供一些模拟的回复:

var sendSpy = spyOn(WebSocket.prototype, "send").and.callFake(function(outMsg){
  // process/check outgoing message
  // setTimeout, or call it immediately
  this.onmessage("mock message goes here");
}); 

但在使用WebSocket.prototype替换之前,请务必使用WebSocketSpy

如此完整的工作示例,应该如下所示:

it("should spy and callFake WebSocket constructor, and stub prototype methods", function (done) {
    var realWS= WebSocket;  
    var sendSpy = spyOn(WebSocket.prototype, "send").and.callFake(function(outMsg){
      if(outMsg == "outgoing message"){
        this.onmessage("incoming mocked message goes here");
      }
    });  
    // var messageSpy = spyOn(WebSocket.prototype, "onmessage");//.and.returnValue("mock message goes here");      
    var WSSpy = spyOn(window, "WebSocket").and.callFake(function(url,protocols){
      return new realWS(url,protocols);
    }); 
    var onmessageCallbackSpy = jasmine.createSpy('onmessageCallback');       

    // Your code
    // (function init(url, onmessageCallbackSpy){
        var ws = new WebSocket("ws://some/where");
        ws.onmessage = onmessageCallbackSpy;
        // code that results with receiving a message
        // or mocked send, that calls `.onmessage` immediately
        ws.send("outgoing message");
    // })();    

    expect(WSSpy).toHaveBeenCalledWith("ws://some/where");
    expect(onmessageCallbackSpy).toHaveBeenCalledWith("mock message goes here");
    done();
});

答案 1 :(得分:3)

我遇到它试图模仿websocket进行茉莉花测试。这是一个使用相当广泛的模拟窗口的解决方案.WebSocket。

var socketMock;
var windowMock;
var address = 'ws://test.address';

describe(".init(address, window)", function() {
  beforeEach(function() {
    var WebSocket = jasmine.createSpy();
    WebSocket.and.callFake(function (url) {
      socketMock = {
        url: url,
        readyState: WebSocket.CONNECTING,
        send: jasmine.createSpy(),
        close: jasmine.createSpy().and.callFake(function () {
          socketMock.readyState = WebSocket.CLOSING;
        }),

        // methods to mock the internal behaviour of the real WebSocket
        _open: function () {
          socketMock.readyState = WebSocket.OPEN;
          socketMock.onopen && socketMock.onopen();
        },
        _message: function (msg) {
          socketMock.onmessage && socketMock.onmessage({data: msg});
        },
        _error: function () {
          socketMock.readyState = WebSocket.CLOSED;
          socketMock.onerror && socketMock.onerror();
        },
        _close: function () {
          socketMock.readyState = WebSocket.CLOSED;
          socketMock.onclose && socketMock.onclose();
        }
      };
      return socketMock;
    });
    WebSocket.CONNECTING = 0;
    WebSocket.OPEN = 1;
    WebSocket.CLOSING = 2;
    WebSocket.CLOSED = 3;

    windowMock = {
      WebSocket: WebSocket
    };
    spyOn(subject, 'handleMessage');
  });

  it("should create a WebSocket client which connects to the given address", function() {
    subject.init(address, windowMock);
    expect(windowMock.WebSocket).toHaveBeenCalledWith(address);
  });

  it("should have onmessage method overriden with a function which handles message", function() {
    var message = 'hello socket';
    subject.init(address, window);

    // pretend the socket connected (optional)
    socketMock._open();

    // pretend the socket got a message
    socketMock._message(message)

    expect(subject.handleMessage).toHaveBeenCalledWith(message);
  });
});