Как проверить обратный вызов функции fs.read

Я хочу протестировать следующий код.

      class Tailer {

  constructor(logFilePath) {
    this.logFilePath = logFilePath;
    this.seekFrom = 0;
    this.lastLines = [];
  }

  setupFile(newlinepointer) {
    var bytesToRead = this.fileSizeInBytes - newlinepointer
    fs.open(this.logFilePath, 'r', (errOpen, fd) => {
      fs.read(fd, Buffer.alloc(bytesToRead), 0, bytesToRead, newlinepointer, (errRead, bytesRead, buffer) => {
        var data = buffer.toString('utf8')
        this.lastLines = data.split('\n')        
      });
    });
  }
}

Мой тестовый код

      describe("tailer", function() {
  describe("setupFile", function() {
    it("should fill last 10 lines from given pointer", function() {
      let tailer = new Tailer('test/test.log', (data) => {})
      tailer.setupFile(5)
      assert.equal(tailer.lastLines.length, 10);
    });
  });
});

Поскольку fs.read использует обратный вызов, я не могу протестировать функцию как lastLines поле еще не заполнено после звонка setupFile. я использую mocha для тестов.

1 ответ

Вы должны использовать библиотеку-заглушку sinonjs для заглушки fs.open() и fs.read()методы. Предоставьте им поддельные реализации. Затем вы можете выполнить обратный вызов вручную в своем тестовом примере.

Например

index.js:

      import fs from 'fs';

export class Tailer {
  logFilePath;
  seekFrom;
  lastLines;
  fileSizeInBytes;

  constructor(logFilePath) {
    this.logFilePath = logFilePath;
    this.seekFrom = 0;
    this.lastLines = [];
    this.fileSizeInBytes = 100;
  }

  setupFile(newlinepointer) {
    var bytesToRead = this.fileSizeInBytes - newlinepointer;
    fs.open(this.logFilePath, 'r', (errOpen, fd) => {
      fs.read(fd, Buffer.alloc(bytesToRead), 0, bytesToRead, newlinepointer, (errRead, bytesRead, buffer) => {
        var data = buffer.toString('utf8');
        this.lastLines = data.split('\n');
      });
    });
  }
}

index.test.js:

      import { Tailer } from './';
import fs from 'fs';
import sinon from 'sinon';
import { expect } from 'chai';

describe('66332328', () => {
  it('should pass', () => {
    const openStub = sinon.stub(fs, 'open').callsFake((filepath, flags, callback) => {
      callback(null, 1);
    });
    const readStub = sinon.stub(fs, 'read').callsFake((fd, buffer, offset, length, position, callback) => {
      callback && callback(null, 100, Buffer.from('teresa teng\nbest singer'));
    });

    const tailer = new Tailer('./test.text');
    tailer.setupFile(50);
    expect(tailer.lastLines).to.be.deep.equal(['teresa teng', 'best singer']);
    sinon.assert.calledWithExactly(openStub, './test.text', 'r', sinon.match.func);
    sinon.assert.calledWithExactly(readStub, 1, Buffer.alloc(50), 0, 50, 50, sinon.match.func);
  });
});

результат модульного теста:

        66332328
    ✓ should pass


  1 passing (6ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------

исходный код: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/66332328

Другие вопросы по тегам