我在开玩笑地为下面的代码片段编写单元测试时遇到困难:
async addCronJob(props: IAddAndUpdateCronJobDetails) {
const {name, individualSchedule} = props;
const parsedCronTime = convertDateAndTimeToCron(
individualSchedule.timeOfRun,
individualSchedule.dateOfrun
)
const {jobType, dateOfRun, id, timeOfRun} = individualSchedule;
const newJob = new CronJob(
parsedCronTime,
async () => {
return this.sqsService.getSqsApproval({
//some properties
}).then(() => {
//some logic
})
},
null,
false,
'Asia/Singapore'
)
this.schedulerRegistry.addCronJob(name, newJob)
newJob.start()
}
这是我的单元测试:
//at the top
jest.mock('cron', () => {
const mScheduleJob = {start: jest.fn(), stop: jest.fn()};
const mCronJob = jest.fn(() => mScheduleJob);
return {CronJob: mCronJob}
})
***************
describe('addCronJob', () => {
it('should add a new cron job', async (done) => {
const testFn = jest.fn();
const parsedCronTime = convertDateAndTimeToCron(
mockSchedule.timeOfRun,
mockSchedule.dateOfrun
)
const testCronJob = new CronJob(
parsedCronTime,
testFn,
null,
false,
'Asia/Singapore'
);
return dynamicCronService.addCron({//properties}).then(() => {
expect(CronJob).toHaveBeenCalledWith(//properties);
expect(testCronJob.start).toBeCalledTimes(1);
done()
})
})
})
以上测试通过,没有错误。但是,它无法在 cron 作业本身内测试此异步代码块:
async () => {
return this.sqsService.getSqsApproval({
//some properties
}).then(() => {
//some logic
})
}
有人知道如何测试上面的代码块吗?
谢谢!
可能来晚了,但我自己也遇到了这个问题,想分享我的解决方案:
使用方法
async addCronJob(taskName: string, cronEx: string, onTickCallback: () => void | Promise<void>): Promise<void> {
const newJob = new CronJob(cronEx, onTickCallback);
this.schedulerRegistry.addCronJob(taskName, newJob);
newJob.start();
}
测试
it('should create cronJob', async () => {
await service.addCronJob(jobName, testCronExpression, callbackFunction);
expect(schedulerRegistryMock.addCronJob).toHaveBeenCalledWith(jobName, expect.any(CronJob));
jest.advanceTimersByTime(60 * 60 * 1000);
expect(callbackFunction).toHaveBeenCalled();
});
我不必使用测试函数创建测试 cronjob,而是必须模拟我期望 cronjob 在滴答声上调用的实际函数(在您的情况下,我相信应该是 getSqsApproval)。然后我期望用 any CronJob 调用 SchedulerRegistry.addCronJob ,因为我不知道具体的作业。创建一个新工作并在这里期待它是行不通的。
最后,我把时间提前了1小时,因为我的testCronExpression是0 * * * *。您应该根据用于测试的 cron 表达式提前时间。 期望在时间过去后调用回调函数(实际上)对我有用。
希望这有帮助!
@nik m的解决方案有效,但只需添加两点:
1.
在
.spec.ts
文件的模块级别添加以下行:
jest.useFakeTimers()
以我的单元测试实现为参考:
async addRandomCronJob(
name: string,
task: (...params: any[]) => any | void,
cronCommand?: CronCommand,
options?: {
days?: number;
minutes?: number;
seconds?: number; // Added seconds option
weeks?: number;
months?: number;
},
): Promise<void> {
const {
days = 0,
minutes = 0,
seconds = 0, // Default seconds is set to 0
weeks = 0,
months = 0,
} = options || {};
let totalSeconds =
days * 24 * 60 * 60 +
minutes * 60 +
weeks * 7 * 24 * 60 * 60 +
months * 30 * 24 * 60 * 60 +
seconds;
if (totalSeconds < 0) {
throw new Error('At least one interval option must be greater than zero.');
}
if (totalSeconds == 0) {
totalSeconds = 7 * 24 * 60 * 60;
}
const randomSeconds = Math.floor(Math.random() * totalSeconds);
const cronExpression = `${randomSeconds} * * * * *`;
const job = new CronJob(cronExpression, task, cronCommand);
this.schedulerRegistry.addCronJob(name, job);
this.logger.log(
`Job ${name} added with a random cron timing within the specified intervals (every ${randomSeconds} seconds)!`,
);
job.start();
}
describe('addRandomCronJob', () => {
it('should add a cron job with a custom interval of 5 seconds', async () => { // Need to indicate the fn is `async`
const name = 'testJob';
const task = jest.fn(() => console.log("Task executed!"));
const customInterval = { seconds: 5 };
// Instead of creating a mock, use the actual service instance
// Need to prepend the `await` keyword here
await service.addRandomCronJob(name, task, undefined, customInterval);
expect(task).not.toHaveBeenCalled();
expect(schedulerRegistry.addCronJob).toHaveBeenCalledWith(name, expect.any(CronJob));
// https://stackoverflow.com/questions/71469500/how-to-write-a-unit-test-for-cronjob-in-nestjs
jest.advanceTimersByTime(1000 * 1000);
expect(task).toHaveBeenCalled();
});
});