用笑话对 NodeJS 流进行单元测试 - 超时问题
Unit testing NodeJS stream with jest - timeout issue
给定以下 NodeJS 转换流:
class ObjectToCSVTransform extends Transform {
private hasSetHeaders: boolean;
constructor() {
super({ objectMode: true });
this.hasSetHeaders = false;
}
static create(): ObjectToCSVTransform {
return new this();
}
_write(
object: Record<string, unkwnown>,
_encoding: BufferEncoding,
callback: TransformCallback
): void {
this.push(this.generateCSV(telemetry));
callback();
}
private generateCSV(object: Record<string, unkwnown>): string {
let csv = '';
if (!this.hasSetHeaders) {
csv += this.createCSVHeaders(object);
this.hasSetHeaders = true;
}
csv += this.createRecord(object);
return csv;
}
private createCSVHeaders(object: Record<string, unkwnown>): string {
return `${Object.keys(object)}\n`;
}
private createCSVRecord(object: Record<string, unkwnown>): string {
return `${Object.values(object)}\n`;
}
}
我实现了以下测试用例(使用 jest),以测试给定 “相同类型” 的普通对象流] 预期输出是它们的有效 CSV 表示:
describe('object to csv stream', () => {
const items: Record<string, unknown> = [
{ foo: 1, bar: 2, baz: 3 },
{ foo: 10, bar: 20, baz: 30 },
{ foo: 100, bar: 200, baz: 300 },
];
it('should transform a list of items to csv', (done) => {
const expectedCsv = 'foo,bar,baz\n1,2,3\n10,20,30\n100,200,300\n';
let csv = '';
Readable.from(items)
.pipe(ObjectToCSVTransform.create())
.on('data', (csvResult) => {
csv += csvResult;
console.log(csvResult); // just for debugging purposes
})
.on('end', () => {
console.log('streaming ended'); // just for debugging purposes
expect(csv).toEqual(expectedCsv);
done();
});
});
});
显然,在测试用例实施期间,我想看看我的测试用例是如何失败的:流似乎工作正常,因为它记录了每个预期的 csv 结果行和 'streaming ended'
消息也在流结束后结束,但测试执行根本没有完成。开玩笑的是,超过默认超时时间居然执行完了:
thrown: "Exceeded timeout of 5000 ms for a test. Use
jest.setTimeout(newTimeout) to increase the timeout value, if this is
a long-running test."
我在这里错过了什么?
请注意,我目前正在使用 jest 回调来通知异步操作何时完成。
问题是csv
的返回值与期望值不匹配。实际返回值在末尾包含一个 \n
。如果您将此添加到您的 expectedCsv
字符串,您的测试将通过。
超时错误是一个转移注意力的错误。
如果您在 'end' 函数中 console.log(csv.replace(/\n/g, '\n'))
,您将在字符串末尾看到额外的换行符。
import { Readable, Transform, TransformCallback } from 'stream';
class ObjectToCSVTransform extends Transform {
private hasSetHeaders: boolean;
constructor() {
super({ objectMode: true });
this.hasSetHeaders = false;
}
static create(): ObjectToCSVTransform {
return new this();
}
// eslint-disable-next-line no-underscore-dangle
_write(
object: Record<string, unknown>,
_encoding: 'utf8',
callback: TransformCallback,
): void {
this.push(this.generateCSV(object));
callback();
}
private generateCSV(object: Record<string, unknown>): string {
let csv = '';
if (!this.hasSetHeaders) {
csv += this.createCSVHeaders(object);
this.hasSetHeaders = true;
}
csv += this.createCSVRecord(object);
return csv;
}
private createCSVHeaders(object: Record<string, unknown>): string {
return `${Object.keys(object)}\n`;
}
private createCSVRecord(object: Record<string, unknown>): string {
return `${Object.values(object)}\n`;
}
}
describe('object to csv stream', () => {
const items: Record<string, unknown>[] = [
{ foo: 1, bar: 2, baz: 3 },
{ foo: 10, bar: 20, baz: 30 },
{ foo: 100, bar: 200, baz: 300 },
];
it('should transform a list of items to csv', (done) => {
const expectedCsv = 'foo,bar,baz\n1,2,3\n10,20,30\n100,200,300\n';
let csv = '';
Readable.from(items)
.pipe(ObjectToCSVTransform.create())
.on('data', (csvResult) => {
csv += csvResult;
console.log(csvResult); // just for debugging purposes
})
.on('end', () => {
console.log('streaming ended'); // just for debugging purposes
console.log(csv.replace(/\n/g, '\n'));
expect(csv).toEqual(expectedCsv);
done();
});
});
});
我的测试用例中缺少一些东西,它根本没有正确处理异步,因此使 Exceeded timeout exception
被开玩笑抛出:
- 用 try-catch 包围断言,并在断言失败时调用
done()
回调。
.on('end', () => {
try {
expect(csv).toEqual(expectedCsv);
done();
} catch (error) {
done(error);
}
});
有关更多信息/参考,请查看笑话文档:https://jestjs.io/docs/asynchronous#callbacks
给定以下 NodeJS 转换流:
class ObjectToCSVTransform extends Transform {
private hasSetHeaders: boolean;
constructor() {
super({ objectMode: true });
this.hasSetHeaders = false;
}
static create(): ObjectToCSVTransform {
return new this();
}
_write(
object: Record<string, unkwnown>,
_encoding: BufferEncoding,
callback: TransformCallback
): void {
this.push(this.generateCSV(telemetry));
callback();
}
private generateCSV(object: Record<string, unkwnown>): string {
let csv = '';
if (!this.hasSetHeaders) {
csv += this.createCSVHeaders(object);
this.hasSetHeaders = true;
}
csv += this.createRecord(object);
return csv;
}
private createCSVHeaders(object: Record<string, unkwnown>): string {
return `${Object.keys(object)}\n`;
}
private createCSVRecord(object: Record<string, unkwnown>): string {
return `${Object.values(object)}\n`;
}
}
我实现了以下测试用例(使用 jest),以测试给定 “相同类型” 的普通对象流] 预期输出是它们的有效 CSV 表示:
describe('object to csv stream', () => {
const items: Record<string, unknown> = [
{ foo: 1, bar: 2, baz: 3 },
{ foo: 10, bar: 20, baz: 30 },
{ foo: 100, bar: 200, baz: 300 },
];
it('should transform a list of items to csv', (done) => {
const expectedCsv = 'foo,bar,baz\n1,2,3\n10,20,30\n100,200,300\n';
let csv = '';
Readable.from(items)
.pipe(ObjectToCSVTransform.create())
.on('data', (csvResult) => {
csv += csvResult;
console.log(csvResult); // just for debugging purposes
})
.on('end', () => {
console.log('streaming ended'); // just for debugging purposes
expect(csv).toEqual(expectedCsv);
done();
});
});
});
显然,在测试用例实施期间,我想看看我的测试用例是如何失败的:流似乎工作正常,因为它记录了每个预期的 csv 结果行和 'streaming ended'
消息也在流结束后结束,但测试执行根本没有完成。开玩笑的是,超过默认超时时间居然执行完了:
thrown: "Exceeded timeout of 5000 ms for a test. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
我在这里错过了什么?
请注意,我目前正在使用 jest 回调来通知异步操作何时完成。
问题是csv
的返回值与期望值不匹配。实际返回值在末尾包含一个 \n
。如果您将此添加到您的 expectedCsv
字符串,您的测试将通过。
超时错误是一个转移注意力的错误。
如果您在 'end' 函数中 console.log(csv.replace(/\n/g, '\n'))
,您将在字符串末尾看到额外的换行符。
import { Readable, Transform, TransformCallback } from 'stream';
class ObjectToCSVTransform extends Transform {
private hasSetHeaders: boolean;
constructor() {
super({ objectMode: true });
this.hasSetHeaders = false;
}
static create(): ObjectToCSVTransform {
return new this();
}
// eslint-disable-next-line no-underscore-dangle
_write(
object: Record<string, unknown>,
_encoding: 'utf8',
callback: TransformCallback,
): void {
this.push(this.generateCSV(object));
callback();
}
private generateCSV(object: Record<string, unknown>): string {
let csv = '';
if (!this.hasSetHeaders) {
csv += this.createCSVHeaders(object);
this.hasSetHeaders = true;
}
csv += this.createCSVRecord(object);
return csv;
}
private createCSVHeaders(object: Record<string, unknown>): string {
return `${Object.keys(object)}\n`;
}
private createCSVRecord(object: Record<string, unknown>): string {
return `${Object.values(object)}\n`;
}
}
describe('object to csv stream', () => {
const items: Record<string, unknown>[] = [
{ foo: 1, bar: 2, baz: 3 },
{ foo: 10, bar: 20, baz: 30 },
{ foo: 100, bar: 200, baz: 300 },
];
it('should transform a list of items to csv', (done) => {
const expectedCsv = 'foo,bar,baz\n1,2,3\n10,20,30\n100,200,300\n';
let csv = '';
Readable.from(items)
.pipe(ObjectToCSVTransform.create())
.on('data', (csvResult) => {
csv += csvResult;
console.log(csvResult); // just for debugging purposes
})
.on('end', () => {
console.log('streaming ended'); // just for debugging purposes
console.log(csv.replace(/\n/g, '\n'));
expect(csv).toEqual(expectedCsv);
done();
});
});
});
我的测试用例中缺少一些东西,它根本没有正确处理异步,因此使 Exceeded timeout exception
被开玩笑抛出:
- 用 try-catch 包围断言,并在断言失败时调用
done()
回调。
.on('end', () => {
try {
expect(csv).toEqual(expectedCsv);
done();
} catch (error) {
done(error);
}
});
有关更多信息/参考,请查看笑话文档:https://jestjs.io/docs/asynchronous#callbacks