我有一个名为ReportHandler
的类,它依赖于其他类(ReportService
,S3Handlere
),像这样:
S3Handler
:用于将文件上传到S3的类ReportService
:正在对数据库执行CRUDhandleReportAsync
是从S3下载文件,执行一些逻辑并将文件更新到数据库的功能。
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;
});
});
});
欢迎任何意见!预先感谢。
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