Как заглушить класс внедрения зависимостей с помощью Sinon. js? - PullRequest
0 голосов
/ 16 января 2020

У меня есть класс с именем ReportHandler, который зависит от других классов (ReportService, S3Handlere), таких как этот:

  • S3Handler: класс для загрузки, загрузки файла в S3
  • ReportService: Выполнение CRUD для базы данных

handleReportAsync - это функция, которая загружает файл из S3, выполняет некоторые логические операции c и обновляет файл в базе данных.

export class ReportHandler {
  private s3Handler;
  private reportService;

  public constructor(reportService) {
    this.reportService = reportService;;

    const accessKey = process.env.AWS_ACCESS_KEY;
    const secretKey = process.env.AWS_SECRET_ACCESS_KEY;
    const bucketName = process.env.AWS_BUCKET_NAME;
    this.s3Handler = new S3Handler(accessKey, secretKey, bucketName);
  }
  public async handleReportAsync(report) {
    try {
      const data = await this.s3Handler.downloadFile(report.id);
      // do some logic
      reportService.updateFile(report.id, data.Body);
    } catch (error) {
    }
  }
}

Я хочу проверить, вызван ли reportService.updateFile() или нет, поэтому я буду использовать spy для этой задачи.

И, очевидно, я не хочу скачать реальный файл с S3 так, как я могу заглушить функцию this.s3Handler.downloadFile() с помощью Sinon.js. Это моя попытка, но безуспешно.

describe("ReportHandler", () => {
  describe("handleReportAsync", () => {
    let sandbox;
    beforeEach(() => {
      sandbox = Sinon.createSandbox();
    });

    afterEach(() => {
      sandbox.restore();
    });
    it("should call updateFile() function", async () => {
      const report = new Report(faker.random.uuid());
      sandbox.stub(S3Handler.prototype, "downloadFile").callsFake(
        (id)  => {},
      );

      sandbox.stub(ReportService.prototype, "updateFile").callsFake(
        (id, file) => {},
      );
      const reportHandler = new ReportHandler(new ReportService());
      const spy = Sinon.spy(ReportService.prototype, "updateFile");
      await reportHandler.handleReportAsync(report);
      expect(spy.called).to.be.true;
    });
  });
});

Любой совет приветствуется! Заранее спасибо.

1 Ответ

0 голосов
/ 16 января 2020

Вот решение для модульного тестирования:

reportHandler.ts:

import S3Handler from "./s3Handler";

export class ReportHandler {
  private s3Handler;
  private reportService;

  public constructor(reportService) {
    this.reportService = reportService;

    const accessKey = process.env.AWS_ACCESS_KEY;
    const secretKey = process.env.AWS_SECRET_ACCESS_KEY;
    const bucketName = process.env.AWS_BUCKET_NAME;
    this.s3Handler = new S3Handler(accessKey, secretKey, bucketName);
  }
  public async handleReportAsync(report) {
    try {
      const data = await this.s3Handler.downloadFile(report.id);
      this.reportService.updateFile(report.id, data.Body);
    } catch (error) {}
  }
}

s3Handler.ts:

export default class S3Handler {
  constructor(accessKey, secretKey, bucketName) {}
}

reportHandler.test.ts:

import { ReportHandler } from "./reportHandler";
import sinon from "sinon";

describe("59766312", () => {
  let sandbox;
  beforeEach(() => {
    sandbox = sinon.createSandbox();
  });

  afterEach(() => {
    sandbox.restore();
  });
  describe("#handleReportAsync", () => {
    it("should update file", async () => {
      const reportServiceStub = { updateFile: sandbox.stub() };
      const s3Handler = require("./s3Handler");
      const downloadFileStub = sandbox.stub().resolves({ Body: "a" });
      const s3HandlerInstanceStub = { downloadFile: downloadFileStub };
      const s3HandlerStub = sandbox.stub(s3Handler, "default").callsFake(() => s3HandlerInstanceStub);
      const reportHandler = new ReportHandler(reportServiceStub);
      const report = { id: 1 };
      await reportHandler.handleReportAsync(report);
      sandbox.assert.calledOnce(s3HandlerStub);
      sandbox.assert.calledWithExactly(s3HandlerInstanceStub.downloadFile, 1);
      sandbox.assert.calledWithExactly(reportServiceStub.updateFile, 1, "a");
    });
  });
});

Результаты модульных испытаний с отчетом о покрытии:

 59766312
    #handleReportAsync
      ✓ should update file


  1 passing (12ms)

-----------------------|----------|----------|----------|----------|-------------------|
File                   |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------------|----------|----------|----------|----------|-------------------|
All files              |      100 |      100 |    90.91 |      100 |                   |
 reportHandler.test.ts |      100 |      100 |      100 |      100 |                   |
 reportHandler.ts      |      100 |      100 |      100 |      100 |                   |
 s3Handler.ts          |      100 |      100 |       50 |      100 |                   |
-----------------------|----------|----------|----------|----------|-------------------|

Исходный код: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/59766312

...