2013-03-19 11 views
45

Kann jemand einen felsenfesten, tod-einfachen Komponententest für Node.js mit WebSockets (Socket.io) bieten?Komponententest Node.js und WebSockets (Socket.io)

Ich benutze socket.io für Node.js, und habe auf socket.io-Client für den Aufbau der Client-Verbindung zu einem Server im Test untersucht. Allerdings scheint mir etwas zu fehlen.

Im folgenden Beispiel wird "bearbeitet ..." nie ausgedruckt.

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

    }); 
}); 

Stattdessen bekomme ich einfach:

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


    1 test complete (26 ms) 

Irgendwelche Vorschläge?

+2

Wird dieser Mokka oder Jasmin getestet? Für asynchrone Mocha-Tests (was das ist) muss Ihre Testfunktion eine Callback-Funktion (testDone) haben, damit mocha weiß, wie man sie richtig behandelt. Dies funktioniert möglicherweise, aber Mocha wird beendet, bevor das Ereignis "connect" ausgelöst wird, weil Mocha nicht weiß, dass es warten soll. –

Antwort

47

Nach weiteren stochern und stoßen, fand ich einige unglaublich nützliche Informationen unter http://blog.foundry376.com/2012/09/connecting-to-a-socket-io-server-from-node-js-unit-tests. Im Beispiel des Autors weist er auf den kritischen Schritt hin, Socket-Listener in den "before *" - Hooks zu etablieren. Dieses Beispiel funktioniert (vorausgesetzt, ein Server für Socket-Verbindungen auf localhost hört: 3001, natürlich)

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

    }); 

}); 

ich, dass die Platzierung von done gefunden() in den before, socket.on ('connect' ...) Der Zuhörer war entscheidend für den Aufbau der Verbindung. Wenn Sie z. B. done() im Listener kommentieren und dann einen Bereich hinzufügen (kurz bevor Sie den beforeEach-Befehl beenden), wird die Meldung "no connection to break ..." statt der Meldung "disconnecting .." angezeigt. ." Botschaft. Wie so:

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

Ich bin neu in Mokka, so gibt es wahrscheinlich einen sehr offensichtlichen Grund für Eingeweihte für die Platzierung erfolgt() withiin den Sockel Umfang selbst. Hoffentlich rettet dieses kleine Detail andere in meinen Schuhen vor dem Haarziehen.

Für mich ist der obige Test (bei korrekter Scoping von done()) Ausgänge:

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

Fügen Sie den Optionen {createNew ': true} hinzu, wenn Sie einen neuen Socket erstellen. Auf diese Weise können Sie in den Komponententests mehrere Client-Sockets erstellen. – HChen

+0

@mysterlune Die done() im Bereich von socket.on ('connect' ...) stellt sicher, dass der Socket sich verbindet, bevor die Tests gestartet werden. Die Operation wird in die Warteschlange gestellt, bis done() im vorherigen Kontext aufgerufen wird. – bucabay

1

Ich hatte dieses Problem: Wie Unit-Test mit einem "socket.io-Client", wenn Sie don zu tun weiß nicht, wie lange der Server braucht, um zu antworten?

Ich habe so mit Mokka und chai gelöst:

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

hier eine Erweiterung der akzeptierten Antwort bietet. Hat grundlegende Client-zu-Server-Kommunikation nützlich als Standard für andere zukünftige Tests. Verwenden von Mokka, Chai und erwarten.

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

});