2015-12-23 3 views
1

Я хотел бы проверить следующий код:вызовы функции тестирования, которые зависят от объекта, возвращенного обратного вызова

'use strict'; 

const amqp = require('amqplib'); 
const Promise = require('bluebird'); 

const queueManager = function queueManager() { 
    const amqp_host = 'amqp://' + process.env.AMQP_HOST || 'localhost'; 

    return { 
    setupQueue: Promise.method(function setupQueue(queue) { 
     return amqp.connect(amqp_host) 
     .then(conn => conn.createConfirmChannel()) 
     .tap(channel => channel.assertQueue(queue)); 
    }), 
    enqueueJob: Promise.method(function enqueueJob(channel, queue, job) { 
     return channel.sendToQueue(queue, new Buffer(job)); 
    }), 
    consumeJob: Promise.method(function consumeJob(channel, queue) { 
     return channel.consume(queue, msg => msg); 
    }) 
    }; 
}; 

module.exports = { 
    create: queueManager 
} 

Я хочу, чтобы проверить мои setupQueue, enqueueJob и consumeJob методы, чтобы убедиться, что они делают правильные вещи на сервер AMQP.

Для setupQueue, например, я хочу, чтобы убедиться, что он использует Channel.createConfirmChannel вместо сказать Channel.createChannel и что это также делает Channel.assertQueue.

Однако я не знаю, как это сделать.

Если я высмеиваю переменную amqp с proxyquire, все, что я могу проверить, это вызов amqp.connect. Я, вероятно, закрою его, чтобы избежать попадания на любые серверы AMQP. Но как насчет следующих утверждений? Как подключиться к объектам conn и channel?

+0

Почему вы не расщепляется свои методы? Затем используйте setupQueue: setupQueue, ... Затем вы можете проверить свои методы индивидуально. – Ludo

ответ

0

Я бы рекомендовал использовать шаблон Dependency Injection.

Зависимость от инъекции - это, на мой взгляд, золотой билет для легкого модульного тестирования. Это касается не только этого конкретного теста, но и всех тестов, которые вы будете писать.

Для достижения этой цели, вы должны

  1. Сплита ваших методов
  2. Использовать инъекции зависимостей
  3. в этих методах
  4. Может быть сделать конструктор для queueManager, чтобы получить доступ к соединению
  5. Использование SinonJs библиотеки к заглушке/макет/шпион.

Это будет выглядеть примерно так

var channelFactory = (conn) => conn.createConfirmChannel(); 
 

 
function QueueManager(queue, channelFactory){ 
 
    this.queue = queue; 
 
    this.channelFactory = channelFactory; 
 
} 
 

 
QueueManager.prototype.setupQueue =() => 
 
    (var scope = this) 
 
     .channelFactory() 
 
     .then((channel) => (scope.channel = channel).assertQueue(scope.queue); 
 

 
QueueManager.enqueueJob = (channel, queue, job) => channel.sendToQueue(queue, new Buffer(job)); 
 
QueueManager.consumeJob = (channel, queue) => channel.consume(queue, msg => msg); 
 

 
// Unit tests 
 

 
describe('setupQueue',() => { 
 
    it('should do smth', (done) => { 
 
    
 
    var host   = 'localhost', 
 
     conn   = new connection(host), 
 
     queue   = new queue(), 
 
     aChannelFactory = channelFactory.bind(queue, conn), 
 
     queueManager = new QueueManager(queue, aChannelFactory), 
 
     spy    = sinon.spy(channel.conn, 'createConfirmChannel'); 
 
    
 
    queueManager 
 
     .setupQueue() 
 
     .then(() => { assert.spy.calledOnce(); done(); }) 
 
     .fail((err) => { done(err); }) 
 
     .finally(() => { spy.restore(); }) 
 
    }) 
 
})

+0

Если я ничего не пропустил, это не будет работать в тесте: 'var spy = sinon.spy (conn, 'createConfirmChannel');' потому что 'conn' не определено, поскольку оно живет в' queueManager' и является результатом обратного вызова 'amqp.connect'. – springloaded

+0

Да, я просто дал вам обзор того, как настроить модульный тест. У меня нет полного кода, поэтому я не могу сказать вам точно, что делать, но вы поняли. – Ludo

+0

Но то же самое относится. Если у вас есть зависимость, сделайте так, чтобы вы могли передать ее. в этом случае, если setupQueue имеет зависимость от объекта соединения, передайте его в аргументах. Используйте инъекцию зависимостей. Делает тесты на запись намного проще. – Ludo