NodeJS 单元测试 RabbitMQ / Amqplib

NodeJS Unit Test RabbitMQ / Amqplib

我正在尝试为我的项目开发测试,我有一个连接到 rabbitmq 并使用队列的文件,但我在想测试它时遇到问题

const amqp = require('amqplib/callback_api');

const rabbitConsumer = (io) => {
  setTimeout(() => {
    amqp.connect('amqp://rabbitmq', (error0, connection) => {
      if (error0) {
        throw error0;
      }
      connection.createChannel((error1, channel) => {
        if (error1) {
          throw error1;
        }
        const queue = 'message';

        channel.assertQueue(queue, {
          durable: false,
        });

        console.log(' [*] Waiting for message', queue);

        channel.consume(
          queue,
          (data) => {
            console.log(' [x] Received data:', data.content.toString('utf-8'));
            io.emit('sendMessage', data.content.toString('utf-8'));
          },
          {
            noAck: true,
          }
        );
      });
    });
  }, 10000);
};

module.exports = rabbitConsumer;

可以测试这个文件吗?我如何使用 JEST 或任何其他库来做到这一点?

您可以使用 jest.spyOn(object, methodName)amqp 对象的方法创建模拟。

使用jest.useFakeTimers(implementation?: 'modern' | 'legacy')告诉jest使用setTimeout函数的假版本,这样你就不需要等待真正的延迟时间。

使用jest.advanceTimersByTime(msToRun)

When this API is called, all timers are advanced by msToRun milliseconds. All pending "macro-tasks" that have been queued via setTimeout() or setInterval(), and would be executed within this time frame will be executed

例如

index.js:

const amqp = require('amqplib/callback_api');

const rabbitConsumer = (io) => {
  setTimeout(() => {
    amqp.connect('amqp://rabbitmq', (error0, connection) => {
      if (error0) {
        throw error0;
      }
      connection.createChannel((error1, channel) => {
        if (error1) {
          throw error1;
        }
        const queue = 'message';
        channel.assertQueue(queue, { durable: false });
        console.log(' [*] Waiting for message', queue);
        channel.consume(
          queue,
          (data) => {
            console.log(' [x] Received data:', data.content.toString('utf-8'));
            io.emit('sendMessage', data.content.toString('utf-8'));
          },
          { noAck: true }
        );
      });
    });
  }, 10000);
};

module.exports = rabbitConsumer;

index.test.js:

const amqp = require('amqplib/callback_api');
const rabbitConsumer = require('./');

describe('rabbitConsumer', () => {
  beforeAll(() => {
    jest.useFakeTimers();
  });
  afterAll(() => {
    jest.useRealTimers();
  });
  test('should pass', () => {
    const mData = {
      content: 'teresa teng',
    };
    const mChannel = {
      assertQueue: jest.fn(),
      consume: jest.fn().mockImplementation((queue, callback) => {
        callback(mData);
      }),
    };
    const mConnection = {
      createChannel: jest.fn().mockImplementation((callback) => {
        callback(null, mChannel);
      }),
    };
    jest.spyOn(amqp, 'connect').mockImplementation((url, callback) => {
      callback(null, mConnection);
    });
    const mIO = {
      emit: jest.fn(),
    };
    rabbitConsumer(mIO);
    jest.advanceTimersByTime(10000);
    expect(amqp.connect).toBeCalledWith('amqp://rabbitmq', expect.any(Function));
    expect(mConnection.createChannel).toBeCalledWith(expect.any(Function));
    expect(mChannel.assertQueue).toBeCalledWith('message', { durable: false });
    expect(mChannel.consume).toBeCalledWith('message', expect.any(Function), { noAck: true });
  });
});

测试结果:

 PASS  examples/69715530/index.test.js (21.564 s)
  rabbitConsumer
    ✓ should pass (27 ms)

  console.log
     [*] Waiting for message message

      at examples/69715530/index.js:15:17

  console.log
     [x] Received data: teresa teng

      at channel.consume.noAck (examples/69715530/index.js:19:21)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |    87.5 |       50 |     100 |    87.5 |                   
 index.js |    87.5 |       50 |     100 |    87.5 | 7,11              
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        23.222 s

您可以创建模拟错误并将它们传递给模拟实现的 callback 以测试错误处理程序分支。