2013-03-19 21 views
45

Czy ktoś mógłby dostarczyć solidnego, martwego prostego testu jednostkowego dla Node.js za pomocą WebSockets (Socket.io)?Testy jednostkowe Node.js i WebSockets (Socket.io)

Używam socket.io dla Node.js, i przyjrzałem się klientowi socket.io, aby ustanowić połączenie klienta z serwerem w teście. Jednak wydaje mi się, że czegoś brakuje.

W poniższym przykładzie "działa ..." nigdy nie zostanie wydrukowane.

var io = require('socket.io-client') 
, assert = require('assert') 
, expect = require('expect.js'); 

describe('Suite of unit tests', function() { 

    describe('First (hopefully useful) test', function() { 

     var socket = io.connect('http://localhost:3001'); 
     socket.on('connect', function(done) { 
      console.log('worked...'); 
      done(); 
     }); 

     it('Doing some things with indexOf()', function() { 
      expect([1, 2, 3].indexOf(5)).to.be.equal(-1); 
      expect([1, 2, 3].indexOf(0)).to.be.equal(-1); 
     }); 

    }); 
}); 

Zamiast tego, po prostu dostać:

Suite of unit tests 
    First (hopefully useful) test 
     ✓ Doing some things with indexOf() 


    1 test complete (26 ms) 

sugestie?

+2

Czy to testy mokka lub jaśminu? W przypadku asynchronicznych testów mokka (które to jest) twoja funkcja testowa musi przyjąć funkcję 'callback (testDone)', więc mocha wie, aby traktować ją odpowiednio. To może faktycznie działać, ale mocha wychodzi przed wyzwaniem "connect", ponieważ mocha nie wie, że powinien poczekać. –

Odpowiedz

47

Po dalszym szturchaniu i szturchaniu znalazłem niewiarygodnie przydatne informacje pod numerem http://blog.foundry376.com/2012/09/connecting-to-a-socket-io-server-from-node-js-unit-tests. W przykładzie autora wskazuje krytyczny krok ustanawiania detektorów gniazd w hakach "przed *". Ten przykład działa (przy założeniu, że serwer nasłuchuje połączeń gniazd na localhost: 3001, oczywiście)

var io = require('socket.io-client') 
, assert = require('assert') 
, expect = require('expect.js'); 

describe('Suite of unit tests', function() { 

    var socket; 

    beforeEach(function(done) { 
     // Setup 
     socket = io.connect('http://localhost:3001', { 
      'reconnection delay' : 0 
      , 'reopen delay' : 0 
      , 'force new connection' : true 
     }); 
     socket.on('connect', function() { 
      console.log('worked...'); 
      done(); 
     }); 
     socket.on('disconnect', function() { 
      console.log('disconnected...'); 
     }) 
    }); 

    afterEach(function(done) { 
     // Cleanup 
     if(socket.connected) { 
      console.log('disconnecting...'); 
      socket.disconnect(); 
     } else { 
      // There will not be a connection unless you have done() in beforeEach, socket.on('connect'...) 
      console.log('no connection to break...'); 
     } 
     done(); 
    }); 

    describe('First (hopefully useful) test', function() { 

     it('Doing some things with indexOf()', function(done) { 
      expect([1, 2, 3].indexOf(5)).to.be.equal(-1); 
      expect([1, 2, 3].indexOf(0)).to.be.equal(-1); 
      done(); 
     }); 

     it('Doing something else with indexOf()', function(done) { 
      expect([1, 2, 3].indexOf(5)).to.be.equal(-1); 
      expect([1, 2, 3].indexOf(0)).to.be.equal(-1); 
      done(); 
     }); 

    }); 

}); 

I stwierdził, że umieszczenie done() w beforeEach, socket.on ('connect' ...) słuchacz miał kluczowe znaczenie dla ustanowienia połączenia. Na przykład, jeśli skomentujesz done() w detektorze, a następnie dodasz jeden zasięg poza (tuż przed wyjściem z beforeEach), zobaczysz komunikat "brak połączenia z przerwą ..." zamiast "odłączania .. . "wiadomość. Tak:

beforeEach(function(done) { 
    // Setup 
    socket = io.connect('http://localhost:3001', { 
     'reconnection delay' : 0 
     , 'reopen delay' : 0 
     , 'force new connection' : true 
    }); 
    socket.on('connect', function() { 
     console.log('worked...'); 
     //done(); 
    }); 
    socket.on('disconnect', function() { 
     console.log('disconnected...'); 
    }); 
    done(); 
}); 

Jestem nowy Mocha, więc prawdopodobnie jest to bardzo oczywistego powodu, dla wtajemniczonych za wprowadzenie zrobić() Withiin samego zakresu sieciowego. Mam nadzieję, że ten drobny szczegół uratuje innych w moich butach przed ciągnięciem włosów.

Dla mnie powyższe testy (z prawidłowym scopingu of done()) Wyjścia:

Suite of unit tests 
    First (hopefully useful) test 
     ◦ Doing some things with indexOf(): worked... 
     ✓ Doing some things with indexOf() 
disconnecting... 
disconnected... 
     ◦ Doing something else with indexOf(): worked... 
     ✓ Doing something else with indexOf() 
disconnecting... 
disconnected... 


    2 tests complete (93 ms) 
+1

Dodaj {'forceNew': true} do opcji przy tworzeniu nowego gniazda. W ten sposób można utworzyć wiele gniazd klientów w testach jednostkowych. – HChen

+0

@mysterlune Funkcja done() w zakresie socket.on ("connect" ...) zapewnia podłączenie gniazda przed rozpoczęciem testów. Operacja jest umieszczana w kolejce, dopóki done() nie zostanie wywołane w poprzednim kontekście. – bucabay

1

miałem ten problem: Jak to zrobić testów jednostkowych z "socket.io-client", jeśli don wiesz, ile czasu zajmuje serwer, aby odpowiedzieć ?.

mam rozwiązany więc korzystanie mokka i chai:

var os = require('os'); 
var should = require("chai").should(); 
var socketio_client = require('socket.io-client'); 

var end_point = 'http://' + os.hostname() + ':8081'; 
var opts = {forceNew: true}; 

describe("async test with socket.io", function() { 
this.timeout(10000); 

it('Response should be an object', function (done) { 
    setTimeout(function() { 
     var socket_client = socketio_client(end_point, opts); 

     socket_client.emit('event', 'ABCDEF'); 

     socket_client.on('event response', function (data) { 
      data.should.be.an('object'); 
      socket_client.disconnect(); 
      done(); 
     }); 

     socket_client.on('event response error', function (data) { 
      console.error(data); 
      socket_client.disconnect(); 
      done(); 
      }); 
     }, 4000); 
    }); 
}); 
4

oferując przedłużenie zaakceptowanej odpowiedzi tutaj. Ma podstawową komunikację między klientem a serwerem, przydatną jako podstawa do przyszłych testów. Za pomocą mocha, chai i oczekiwać.

var io = require('socket.io-client') 
    , io_server = require('socket.io').listen(3001); 

describe('basic socket.io example', function() { 

    var socket; 

    beforeEach(function(done) { 
    // Setup 
    socket = io.connect('http://localhost:3001', { 
     'reconnection delay' : 0 
     , 'reopen delay' : 0 
     , 'force new connection' : true 
     , transports: ['websocket'] 
    }); 

    socket.on('connect',() => { 
     done(); 
    }); 

    socket.on('disconnect',() => { 
     // console.log('disconnected...'); 
    }); 
    }); 

    afterEach((done) => { 
    // Cleanup 
    if(socket.connected) { 
     socket.disconnect(); 
    } 
    io_server.close(); 
    done(); 
    }); 

    it('should communicate', (done) => { 
    // once connected, emit Hello World 
    io_server.emit('echo', 'Hello World'); 

    socket.once('echo', (message) => { 
     // Check that the message matches 
     expect(message).to.equal('Hello World'); 
     done(); 
    }); 

    io_server.on('connection', (socket) => { 
     expect(socket).to.not.be.null; 
    }); 
    }); 

});