用Jasmine在JavaScript中stubing WebSocket

用Jasmine在JavaScript中stubing WebSocket,javascript,testing,websocket,jasmine,stub,Javascript,Testing,Websocket,Jasmine,Stub,我尝试测试消息上的是否是正确的函数 下面是一个测试: describe(".init(address, window)", function() { beforeEach(function() { address = 'ws://test.address'; window = {}; e = { data: {} } spyOn(window, 'WebSocket').and.returnValue(fun

我尝试测试消息上的
是否是正确的函数

下面是一个测试:

  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;
  }
};

第一次测试通过了。在第二种情况下,
ws
undefined
。为什么呢?我在控制台中尝试了
new function(){return{onmessage:null}
,它看起来应该没问题。

我不完全确定我是否理解了您的代码应该如何运行,但是如果您需要监视
WebSocket
构造函数和存根
。send
方法来模拟一些传入的消息,下面是如何实现它

要监视
WebSocket
,您需要调用
。和.callThrough
,而不是
returnValue
。但是,它的结果是抱怨缺少
new
关键字(如中所述),因此您需要伪造构造函数:

要对传入的消息进行监视,只需执行以下操作

您还可以监视
.send
方法,并提供一些模拟响应,包括:

但在用
WebSocketSpy
替换之前,请确保使用
WebSocket.prototype

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


我在模拟jasmine测试的websocket时遇到了它。下面是一个使用相当广泛的mock window.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);
  });
});
var onmessageCallbackSpy = jasmine.createSpy('onmessageCallback');
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");
}); 
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();
});
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);
  });
});