Подтвердить что ты не робот

Тестирование модулей Node.js и WebSockets (Socket.io)

Может ли кто-нибудь предоставить прочную, мертвую простую unit test для Node.js с помощью WebSockets (Socket.io)?

Я использую socket.io для Node.js, и посмотрел на socket.io-client для установления клиентского соединения с сервером в тесте. Однако, похоже, я что-то упускаю.

В приведенном ниже примере "работало..." никогда не распечатывается.

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

    });
});

Вместо этого я просто получаю:

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


  1 test complete (26 ms)

Любые предложения?

4b9b3361

Ответ 1

После дальнейшего выталкивания и подталкивания я нашел невероятно полезную информацию в http://blog.foundry376.com/2012/09/connecting-to-a-socket-io-server-from-node-js-unit-tests. В примере автора он указывает на критический шаг установки сокет-слушателей в "до *" крючках. Этот пример работает (при условии, что сервер прослушивает подключения сокетов на localhost: 3001, конечно)

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

    });

});

Я обнаружил, что размещение done() в прослушивателе beforeEach, socket.on('connect'...) имеет решающее значение для установления соединения. Например, если вы закомментируете done() в прослушивателе, добавьте его в одну область (непосредственно перед тем, как выйти из beforeEach), вы увидите сообщение "no connection to break..." вместо "отключение".. ". Например:

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

Я новичок в Mocha, поэтому, возможно, очень очевидная причина для инициализации для put done() с самой областью сокета. Надеюсь, эта маленькая деталь спасет других на моих ботинках от вытягивания волос.

Для меня вышеуказанный тест (с правильной оценкой done()) выводит:

  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)

Ответ 2

Предлагая расширение принятого ответа здесь. Имеет базовую клиентскую связь с сервером, полезную в качестве шаблона для других будущих тестов. Использование mocha, chai и ожидать.

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

});

Ответ 3

У меня была эта проблема: как сделать unit test с "socket.io-client", если вы не знаете, сколько времени сервер должен ответить?

Я решил так использовать mocha и 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

Проверьте это шаблонное решение, которое основано на обещаниях и хорошей практике. С его помощью вы можете протестировать все свои события на сервере, без проблем. Вам просто нужно скопировать шаблонный тест и добавить свой собственный код по мере необходимости.

Проверьте репозиторий на GitHub для полного исходного кода.

https://github.com/PatMan10/testing_socketIO_server

const io = require("socket.io-client");
const ev = require("../utils/events");
const logger = require("../utils/logger");

// initSocket returns a promise
// success: resolve a new socket object
// fail: reject a error
const initSocket = () => {
  return new Promise((resolve, reject) => {
      // create socket for communication
      const socket = io("localhost:5000", {
        "reconnection delay": 0,
        "reopen delay": 0,
        "force new connection": true
      });

      // define event handler for sucessfull connection
      socket.on(ev.CONNECT, () => {
        logger.info("connected");
        resolve(socket);
      });

      // if connection takes longer than 5 seconds throw error
      setTimeout(() => {
        reject(new Error("Failed to connect wihtin 5 seconds."));
      }, 5000);
    }
  );
};


// destroySocket returns a promise
// success: resolve true
// fail: resolve false
const destroySocket = socket => {
  return new Promise((resolve, reject) => {
    // check if socket connected
    if (socket.connected) {
      // disconnect socket
      logger.info("disconnecting...");
      socket.disconnect();
      resolve(true);
    } else {
      // not connected
      logger.info("no connection to break...");
      resolve(false);
    }
  });
};

describe("test suit: Echo & Bello", () => {
  test("test: ECHO", async () => {
    // create socket for communication
    const socketClient = await initSocket();

    // create new promise for server response
    const serverResponse = new Promise((resolve, reject) => {
      // define a handler for the test event
      socketClient.on(ev.res_ECHO, data4Client => {
        //process data received from server
        const { message } = data4Client;
        logger.info("Server says: " + message);

        // destroy socket after server responds
        destroySocket(socketClient);

        // return data for testing
        resolve(data4Client);
      });

      // if response takes longer than 5 seconds throw error
      setTimeout(() => {
        reject(new Error("Failed to get reponse, connection timed out..."));
      }, 5000);
    });

    // define data 4 server
    const data4Server = { message: "CLIENT ECHO" };

    // emit event with data to server
    logger.info("Emitting ECHO event");
    socketClient.emit(ev.com_ECHO, data4Server);

    // wait for server to respond
    const { status, message } = await serverResponse;

    // check the response data
    expect(status).toBe(200);
    expect(message).toBe("SERVER ECHO");
  });

  test("test BELLO", async () => {
    const socketClient = await initSocket();
    const serverResponse = new Promise((resolve, reject) => {
      socketClient.on(ev.res_BELLO, data4Client => {
        const { message } = data4Client;
        logger.info("Server says: " + message);
        destroySocket(socketClient);
        resolve(data4Client);
      });

      setTimeout(() => {
        reject(new Error("Failed to get reponse, connection timed out..."));
      }, 5000);
    });

    const data4Server = { message: "CLIENT BELLO" };
    logger.info("Emitting BELLO event");
    socketClient.emit(ev.com_BELLO, data4Server);

    const { status, message } = await serverResponse;
    expect(status).toBe(200);
    expect(message).toBe("SERVER BELLO");
  });
});

---- Foot Note ----

В зависимости от того, как вы настроили свою серверную среду, вы можете столкнуться с конфликтом среды между socket.io и socket.io-client, запущенными из одного проекта одновременно. В этом случае было бы лучше разделить проект на "тестовый клиент" и сервер. Checkout ниже репо, если вы получаете эту проблему.

https://github.com/PatMan10/testing_socketIO_server_v2